Cookie前缀绕过技术揭秘:利用Unicode和解析差异突破__Host-与__Secure-防御

本文深入分析了浏览器__Host-和__Secure- cookie前缀的安全机制,揭示了通过Unicode空白字符编码差异和传统解析漏洞绕过防护的技术细节,包含Django、ASP.NET等框架的实战案例和PoC代码,为Web安全研究人员提供新的攻击视角。

浏览器引入cookie前缀旨在保护会话安全,防止攻击者设置恶意cookie。本文将展示如何利用浏览器与服务器逻辑差异绕过cookie防护机制。

通过Unicode空白字符覆盖Cookie

RFC 6265bis引入cookie前缀强化安全机制:

  • __Host-前缀的cookie必须为host-only(不可跨子域共享)
  • __Secure-前缀的cookie必须来自安全源

这些限制由浏览器强制执行,但浏览器与服务器在cookie编码解析上的不一致会导致微妙而危险的漏洞。根据RFC 6265,Cookie头被定义为八位字节序列而非字符序列,这意味着浏览器发送原始字节,服务器需负责解码。若双方字节解释方式不同,就会产生解析差异。

通过UTF-8编码,攻击者可伪装受限cookie(如以__Host-开头)绕过浏览器保护。浏览器可能将其视为非受限cookie,但服务器解码规范化后可能将其识别为受保护cookie。

以下为概念验证代码:

1
document.cookie=`${String.fromCodePoint(0x2000)}__Host-name=injected; Domain=.example.com; Path=/;`

该带空白前缀的cookie被浏览器视为非前缀非受限值,因此会发送到目标域的所有子域。

测试发现Django、ASP.NET等服务器端框架会对cookie名称进行规范化处理。当服务器将U+2000识别为空白字符时会自动移除,使cookie名变为__Host-name。Django使用Python内置的.strip()方法处理cookie键值,该方法会移除包括[133, 160, 5760, 8192–8202, 8232, 8233, 8239, 8287, 12288]在内的Unicode空白字符。

Safari处理方式不同:不支持多字节Unicode空白字符,但仍允许U+0085(NEL)和U+00A0(不换行空格)等单字节字符。

利用传统解析覆盖Cookie

除Unicode技巧外,传统cookie解析行为也可用于绕过前缀保护。若Cookie头以$Version=1开头,Apache Tomcat等Java服务器会切换至传统解析模式,将单个cookie字符串解析为多个独立cookie:

1
document.cookie=`$Version=1,__Host-name=injected; Path=/somethingreallylong/; Domain=.example.com;`;

此方式可绕过浏览器前缀检查,从子域或不安全源注入高权限cookie。

完整攻击场景

假设存在XSS漏洞且cookie值未转义直接反射到页面。应用使用__Host-前缀cookie,正常情况下浏览器限制可防止不可信子域覆盖。但通过上述技术注入伪造cookie:

1
2
3
document.cookie=`${String.fromCodePoint(0x2000)}__Host-name=<img src=x onerror=alert(1)>; 
Domain=example.com; 
Path=/`

浏览器会同时发送原始cookie和攻击者控制的cookie:

1
Cookie: __Host-name=Carlos;  __Host-name=<img src=x onerror=alert(1)>;

后端解析时若存在同名cookie,Django等框架通常采用最后出现的值,导致攻击值优先。若应用未正确编码反射cookie值,将产生XSS漏洞;若cookie用于CSRF防护或会话识别,可能导致会话固定或权限提升。

Django官方回应指出该攻击依赖允许不可信子域cookie的场景,符合文档警告,因此不作为安全漏洞处理。

技术要点 浏览器与后端对同一cookie的解析差异可能悄无声息地破坏cookie保密性与完整性保证。本文作者已为Burp Suite创建轻量级自定义检测工具,可快速识别后端是否存在cookie前缀绕过漏洞。

本系列前文还演示了通过cookie sandwich技术窃取HttpOnly cookie的方法。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计