HTTP Cookie 安全机制解析
Cookie 基础概念
Cookie 是用于跟踪 HTTP 会话的元数据。由于 HTTP 是无状态协议——每个 HTTP 会话都相互独立,网站通过在浏览器中设置 Cookie 来识别用户。这使得用户能够从上次中断的地方继续浏览活动(例如在线购物),因为浏览器在后续访问该网站时都会包含该 Cookie。
HTTP 头部:Set-Cookie 与 Cookie
根据 RFC 6265,Cookie 包含在 Cookie 或 Set-Cookie 头部字段中。由于网站将 Cookie 设置到客户端浏览器中,Set-Cookie 头部出现在服务器的 HTTP 响应中。当客户端将来返回网站时,它将在 HTTP 请求的 Cookie 头部中包含这些 Cookie。客户端发送的 Cookie 头部包含之前由 Web 服务器在 Set-Cookie 头部中设置的 Cookie。
我们可以通过向最近未访问的网站发送 HTTP 请求来观察 Cookie 头部的设置。以访问 www.cnn.com 并使用 Burp Suite 拦截为例:
首次访问时,浏览器未发送任何 Cookie 头部,因为这是首次访问该 Web 服务器。
服务器在 HTTP 响应中通过 Set-Cookie 头部设置多个 Cookie。例如,cnn.com 设置了以下 4 个 Cookie:
- SecGpc
- countryCode
- stateCode
- geoData
这些 Cookie 专门用于存储客户端的地理位置信息,帮助 cnn.com 根据访问区域自定义内容,并满足基于区域的合规要求。
所有四个 Cookie 都具有 Domain=.cnn.com 属性,这意味着浏览器将在向所有 cnn.com 子域(如 edition.cnn.com、www.cnn.com 等)发出的 HTTP 请求中包含这些 Cookie。
Cookie 属性
RFC 6265 第 4.1.2 节规定:用户代理收到 Set-Cookie 头部时,会存储 Cookie 及其属性。Cookie 属性是控制 Cookie 行为的附加信息,可以确定 Cookie 的过期时间或是否应关联安全措施。
以下属性决定 Cookie 的生命周期:
- Expires:表示 Cookie 的最大生存期,作为过期日期和时间。
- Max-Age:表示 Cookie 的最大生存期,以秒为单位。
如果 Cookie 同时包含这两个属性,则 Max-Age 属性优先并控制 Cookie 的过期日期。
其他属性包括(但不限于):
- Domain:指定用户代理将向其发送 Cookie 的主机。
- Path:将 Cookie 的范围限制到特定路径/URI。
- Secure:用户代理仅通过 HTTPS 在 HTTP 请求中包含此 Cookie。
- HttpOnly:将 Cookie 的范围限制为仅 HTTP,防止脚本(如 JavaScript)访问 Cookie。
Web 应用程序安全
有多种 Cookie 旨在减轻 Web 应用程序安全风险。根据 OWASP,HttpOnly Cookie 有助于减轻客户端脚本访问受保护 Cookie 的风险。支持 HttpOnly 标志的浏览器将防止向第三方透露 Cookie。
跨站脚本(XSS)攻击针对可能包含会话标识符的 Cookie。能够访问 Cookie 的攻击者可以窃取并重放它以冒充受害者,这也称为会话劫持。
测试 HttpOnly 标志
为了测试浏览器如何防止第三方访问启用了 HttpOnly 标志的 Cookie,通过配置 WordPress 网站设置一个带有 HttpOnly 标志的测试 Cookie。在 WordPress 主题的 functions.php 文件中添加以下代码:
|
|
访问网站后,服务器在 HTTP 响应中设置测试 Cookie。在 Google Chrome 开发者工具的 Network -> Cookies 下查看,HttpOnly 已被勾选。
在控制台中运行 document.cookie
命令时,无法看到任何信息,没有输出。这是因为浏览器不允许读取之前存储的测试 Cookie 及其值,因为它具有 HttpOnly 属性。
Web 浏览器中的 document.cookie
属性允许客户端 JavaScript 读取和写入与当前文档关联的 Cookie。但是,使用 HttpOnly 标志设置的 Cookie 是此规则的一个特定例外。
通过修改代码创建一个没有 HttpOnly 标志的新测试 Cookie(名为 new_test_cookie),将 HttpOnly 切换为 ‘false’:
|
|
重新加载页面后,现在看到两个 Cookie。一个未设置 HttpOnly 标志。这次在控制台中运行 document.cookie
时,能够看到新创建的 Cookie 的名称和值。这是因为此 Cookie 未设置 HttpOnly 标志。
启用了 HttpOnly 标志的原始 test_cookie 仍然未显示。类似地,使用 JavaScript 读取或修改 HttpOnly Cookie 的其他尝试都将失败。这是解释浏览器如何保护受害者免受攻击者窃取其会话 ID(SID)的简单方法,因为 Web 服务器选择为敏感 Cookie 赋予 HttpOnly 标志。
实施 HttpOnly
所有 Cookie 都应包含 HttpOnly 属性吗?为了防止敏感数据泄漏,应为此类 Cookie(如会话标识符和身份验证令牌)启用此标志。
相反,有些 Cookie 在设置时未赋予 HttpOnly 标志。一个例子是由反向代理(如 F5)插入的机器人防御 Cookie。这些反向代理将使用 JavaScript 挑战来确定连接的客户端是人类还是机器人。
JavaScript 挑战在浏览器中运行并收集遥测数据(如鼠标移动)。然后使用 JavaScript(通常是 document.cookie
)设置一个 Cookie,以存储遥测令牌,以便在未来的 HTTP 请求中进行验证。
由于 JS 在遥测收集期间需要读取/写入 Cookie,因此不能设置 HttpOnly 属性。