Rudra Analyzer

安全

如何检查 Cookie 安全:Secure、HttpOnly、SameSite 与 Cookie 前缀

会话 Cookie 就是访客账户的钥匙。本文讲解每个 Cookie 属性如何保护它们、怎样检查你自己的 Cookie,以及如何正确设置。

作者:Rudra Techno Team 阅读约 7 分钟
本页内容

用户登录你的网站时,服务器通常会交给浏览器一个会话 Cookie。从那一刻起,谁持有这个 Cookie,谁就是这位用户。Cookie 的各个属性决定了浏览器何时发送它、通过哪些连接发送,以及页面上的脚本能否读取它。配置正确只需要一行代码;配置错了,一个小漏洞就可能演变成账户被接管。

几个关键属性

Secure

Secure 告诉浏览器只通过 HTTPS 发送该 Cookie。没有它,Cookie 就可能随着普通的 HTTP 请求发出去,比如有人输入你的域名时没带 https://,而重定向还没来得及发生,这时同一网络中的任何人都能读到它。在 HTTPS 网站上,每个 Cookie 都应该带 Secure。

HttpOnly

HttpOnly 让 JavaScript(document.cookie)读不到这个 Cookie。即使攻击者设法往你的页面里注入了脚本,也没法轻易读出会话 Cookie 再发往别处。会话 Cookie 和身份验证 Cookie 都应该使用它。至于你自己的前端代码必须读取的 Cookie,比如某些框架特意暴露给 JavaScript 的 CSRF 令牌,就不能设为 HttpOnly,这属于正常情况。

SameSite

SameSite 控制当请求来自其他网站时是否发送该 Cookie:

  • SameSite=Strict:只在从你自己网站发起的请求中发送。最安全,但访客从邮件里的链接点进你的网站时,看上去会是未登录状态。
  • SameSite=Lax:在点击链接这类顶级导航中发送,但跨站的表单提交、图片或框架请求中不发送。很适合作为会话 Cookie 的默认值。
  • SameSite=None:在所有跨站场景中都发送,嵌入式挂件和某些单点登录流程需要它。它必须与 Secure 搭配使用,否则浏览器会拒收这个 Cookie。

基于 Chromium 的浏览器会把没有 SameSite 属性的 Cookie 当作 Lax 处理,但并非所有浏览器都是如此,所以请明确设置。

Domain 与 Path

不写 Domain,Cookie 就是仅限主机的:只发送给设置它的那一台主机。设置 Domain=example.com 则会把它共享给所有子域名,其中包括那些托管在别处、早已被遗忘、安全性可能较差的子域名。只有确实需要在多个子域名之间共享登录状态时,才去扩大作用范围。

Expires 与 Max-Age

没有 Expires 或 Max-Age 的 Cookie,本意是只在浏览器会话期间有效,不过会恢复会话的浏览器可能把它保留得更久。对于持久登录,请根据风险选择合适的有效期,并确保服务器端也会让会话过期。

Cookie 前缀:__Host- 与 __Secure-

Cookie 名称前缀可以让浏览器替你强制执行规则。名称以 __Secure- 开头的 Cookie,只有带 Secure 属性并且通过 HTTPS 设置时才会被接受。以 __Host- 开头的 Cookie 更严格:它必须带 Secure,通过 HTTPS 设置,带有 Path=/,并且不能有 Domain 属性。这样它就被锁定在单个主机上,被攻陷或管理疏忽的子域名无法覆盖它。

对于不需要跨子域名共享的会话 Cookie,__Host- 是现有最强的选择:Set-Cookie: __Host-session=…; Secure; HttpOnly; SameSite=Lax; Path=/。

如何检查你的 Cookie

  1. 在浏览器中。打开开发者工具,进入 Application(Chrome、Edge)或 Storage(Firefox),再点开 Cookies 并选择你的网站。表格中会显示每个 Cookie 的 Domain、Path、Expires、HttpOnly、Secure 和 SameSite 各列。
  2. 在原始响应中。在 Network 面板里点击文档请求,查看 Set-Cookie 响应头。这里显示的正是服务器发出的原样内容,包括可能已被浏览器拒绝的属性。
  3. 登录之后。许多网站只在登录后或创建购物车时才设置重要的 Cookie,所以要在这些页面上再检查一遍。
  4. 使用检查工具。Rudra 的免费安全检查工具会读取页面自身响应中的 Set-Cookie 响应头,并报告以下情况:HTTPS 下没有 Secure 的 Cookie、疑似会话 Cookie 却没有 HttpOnly、SameSite=None 却没有 Secure、没有设置 SameSite 的 Cookie,以及作用域设在父域名上的 Cookie。

自动检查有两点局限值得了解。第一,它是根据名称来判断一个 Cookie 是否“疑似会话 Cookie”的(名称中含有 sess、sid、token 或 auth 之类的字样),因此这类发现的置信度标为中等:请自行确认该 Cookie 实际保存的是什么。第二,它只能看到那一次响应所设置的 Cookie,看不到之后由 JavaScript、其他页面、登录之后或第三方设置的 Cookie。Cookie 的值绝不会被读取或存储。

检查你的 Cookie 标志

输入一个页面,Rudra 就会报告该页面所设置 Cookie 的 Secure、HttpOnly 和 SameSite 标志(只按名称列出),同时给出你的 HTTPS 和响应头配置情况。

检查您的首页 · 免费 · 无需注册

如何在常见平台上设置 Cookie 标志

  • PHP 会话:在 php.ini 中设置 session.cookie_secure = 1、session.cookie_httponly = 1 和 session.cookie_samesite = "Lax"(PHP 7.3 及以上版本),或者把同样的选项传给 session_set_cookie_params()。
  • Django:SESSION_COOKIE_SECURE = True 和 CSRF_COOKIE_SECURE = True。SESSION_COOKIE_HTTPONLY 和 SESSION_COOKIE_SAMESITE = "Lax" 本来就是默认值。
  • Express(Node.js):res.cookie("sid", value, { secure: true, httpOnly: true, sameSite: "lax" }),或者使用 express-session 的 cookie 选项。如果部署在代理之后,请启用 trust proxy,让 Express 知道连接走的是 HTTPS。
  • WordPress:核心的登录 Cookie 带有 HttpOnly,网站运行在 HTTPS 上时还会标记为 Secure。插件的 Cookie 则各不相同;请在开发者工具中检查,如果缺少标志,就去问插件作者。
  • 万不得已时用反向代理:nginx 的 proxy_cookie_flags(1.19.3 及以上版本)可以为你无法修改的应用所发出的 Cookie 加上 secure、httponly 和 samesite。

常见错误

  • 生产环境里给 Cookie 加了 Secure,本地却只用 HTTP 测试,于是“临时”把这个标志关掉。
  • 设置了 SameSite=None 却没有 Secure,结果浏览器丢弃了 Cookie,登录或嵌入功能随之失效。
  • “以防万一”就把会话 Cookie 的作用域设到父域名上。
  • 把会话令牌存在 localStorage 里,任何被注入的脚本都能读到;相比之下 HttpOnly Cookie 更安全。
  • 把个人数据放进 Cookie 的值里。Cookie 里应该放标识符,而不是信息本身。

Cookie 只是全局中的一环。关于响应头、HTTPS 以及被动测试的局限,请阅读如何检查网站安全。

常见问题

是不是每个 Cookie 都应该设为 HttpOnly?

凡是 JavaScript 不需要读取的 Cookie 都应该。会话 Cookie 和身份验证 Cookie 必须始终设为 HttpOnly。偏好设置类的 Cookie,或者前端代码有意读取的令牌,则无法这样设置,这没有问题。

SameSite=Lax 足以防范 CSRF 吗?

它能挡住最常见的跨站表单提交,但单靠它并不构成完整的防御:同站的子域名和顶级 GET 请求仍然可以带上这个 Cookie。对于会改变状态的请求,请继续使用 CSRF 令牌,并且绝不要用 GET 来修改数据。

为什么设置 SameSite=None 之后 Cookie 就不见了?

浏览器会拒收没有同时标记 Secure 的 SameSite=None Cookie。加上 Secure,并通过 HTTPS 提供网站即可。

Rudra 会读取我的 Cookie 值吗?

不会。安全检查工具只记录 Cookie 的名称及其属性。Cookie 的值、令牌以及其中的任何其他内容,都不会被读取、存储或显示。

需要更深入的网站分析?

查看网站上的每个问题,并按修复优先级排序

无需账户即可免费检查任意页面,注册后还可抓取整个网站。每份报告涵盖 SEO、常见性能问题、无障碍和安全,并为每个问题提供修复建议。