Cookie安全属性Secure、HttpOnly
Cookie 是网站用来维持登录状态、记住用户信息的基础机制,但一旦被偷取或伪造,可能导致账号被盗。
给 Cookie 正确配置 Secure、HttpOnly、SameSite 三个安全属性,是低成本且有效的防护手段。
本文按零基础可操作的思路,先解释每个属性的作用,再给出 Nginx、Apache、PHP 等环境下的配置方法,最后介绍如何验证设置是否生效。
三个属性分别解决什么问题
先理解再动手,避免配完不知道效果。
- Secure:标记该属性的 Cookie 只能通过 HTTPS 协议传输。如果你的网站已启用 SSL 证书,加上它可防止明文链路中被抓包获取 Cookie。
- HttpOnly:禁止 JavaScript 读取该 Cookie。它能阻止跨站脚本(XSS)攻击直接偷走登录态。注意它不会拦截 Cookie 的正常发送,只是让
document.cookie看不到它。 - SameSite:控制 Cookie 在跨站请求中是否携带,分三个取值:
Strict完全禁止跨站携带、Lax允许部分安全请求(如导航跳转)携带、None允许全部携带但必须搭配 Secure。现在主流浏览器默认按 Lax 处理,用于防御 CSRF 攻击。
结论:只要条件允许,建议三个属性全部开启。 如果网站依赖跨站登录或支付回调,可把 SameSite 调成 Lax 并单独测试,不要直接改成 None。
配置前需要确认的条件
动手前先检查两点,避免配置无效:
- 网站必须已部署 HTTPS。
Secure属性在 HTTP 环境下不会生效,浏览器甚至可能忽略它。 - 确认你用的是哪种服务环境:Nginx、Apache,还是 PHP 框架直接生成 Cookie。不同环境配置方式不一样,但可以叠加生效。
下面的操作默认你拥有服务器管理员权限,或者能通过宝塔面板等工具修改配置文件。
在 Nginx 中配置 Cookie 安全属性
如果你使用 Nginx 作为反向代理或 Web 服务器,可以通过 proxy_cookie_flags 为上游服务器返回的 Set-Cookie 统一添加属性。
适合代理模式下无法修改后端代码的场景。
在站点配置文件的 location 或 server 块中加入:
proxy_cookie_flags ~ . secure;
proxy_cookie_flags ~ . httponly;
proxy_cookie_flags ~ . samesite=lax;
如果想对特定 Cookie 设置,把 ~ . 换成具体 Cookie 名或正则,例如:
proxy_cookie_flags PHPSESSID secure httponly samesite=lax;
保存后测试并重载配置:
nginx -t
nginx -s reload
注意:proxy_cookie_flags 命令需要 Nginx 版本支持,建议 1.19.3 及以上。
如果你的 Nginx 编译时没有 ngx_http_proxy_module 也会报错,此时需要改用后端程序设置。
在 Apache 中配置 Cookie 安全属性
Apache 使用 Header 指令直接修改响应头。
开启 mod_headers 后,在虚拟主机配置或 .htaccess 中写入:
Header always edit Set-Cookie ^(.*)$ $1;Secure;HttpOnly;SameSite=Lax
这条规则会把所有 Set-Cookie 响应头追加上述属性。
如果只对特定 Cookie 处理,用正则替换指定名称:
Header always edit Set-Cookie ^(.*PHPSESSID.*)$ $1;Secure;HttpOnly;SameSite=Lax
修改后执行 apachectl -t 检查语法,再 systemctl reload httpd(或 apache2)重载。
同 Nginx 一致,
Apache 方式也适合不想改程序代码的场景,
但要注意如果后端已经设置过同名字段,
可能会产生重复值,
浏览器取第一个还是最后一个取决于具体实现,
建议先用下面验证方法检查。
在 PHP 中配置 Cookie 安全属性
PHP 项目可以在两个层面设置,推荐优先在会话配置中操作。
打开 php.ini 找到 session.cookie_secure、session.cookie_httponly 和 session.cookie_samesite,改成:
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
修改后重启 PHP-FPM 或 Apache 服务。
如果你使用 Laravel、ThinkPHP 等框架,通常有独立配置项。
以 Laravel 为例,在 config/session.php 中调整:
'secure' => env('SESSION_SECURE_COOKIE', null),
'http_only' => true,
'same_site' => 'lax',
在框架中设置会覆盖 php.ini 的同名项,所以二选一即可,避免混乱。
验证 Cookie 属性是否生效
配置完成后,不要直接关掉编辑器,先用浏览器打开网站并登录,然后按 F12 打开开发者工具:
- 切换到 Network(网络) 面板。
- 刷新页面,在请求列表中找到文档请求(一般是 HTML 页面)。
- 点击该请求,在 Headers(标头) 中查找
Set-Cookie响应头。 - 检查该行末尾是否带有
Secure、HttpOnly、SameSite=Lax标记。
例如正常效果类似:
Set-Cookie: sessionid=abc123; path=/; Secure; HttpOnly; SameSite=Lax
如果看不到 Secure,先确认当前访问地址是 https:// 开头,并清除浏览器缓存重试。
因为某些开发工具在 HTTP 下会自动过滤显示。
也可以用命令行方式快速检查,适合在 Linux 服务器上测试:
curl -I https://你的域名
从返回的头部中查看 Set-Cookie 值,注意 curl 默认不携带 HTTPS,所以直接使用 URL 即可。
常见坑和避坑建议
SameSite 与 Secure 的组合规则:只有把 SameSite 设为 None 时,Secure 属性才是必须的。
写 Lax 或 Strict 时可以不强制 Secure,但为了安全建议同时保留。
代理层覆盖问题:如果网站前面还有 CDN 或负载均衡,后端设置的 Cookie 属性可能被中间层重写。
需要在最外层代理再校验一次。
PHP 会话名称冲突:多个应用部署在同一域名下,不同 PHP 会话名可能携带不同属性,最好在代码中通过 session_set_cookie_params 单独设置。
不要盲目开启 Strict:如果你的网站和第三方登录、支付平台有跳转交互,同站跨域跳转时 Strict 可能会丢失会话,导致登录回调失败。
一般推荐先使用 Lax,确认无异常后再评估能否升级为 Strict。
完成上述操作后,建议顺手检查其他 Cookie 是否也缺失安全属性。
可以把这些配置写进网站的部署脚本,确保每次上线都自动带上。
排查问题时,优先看浏览器的诊断工具和服务器访问日志,Cookie 配置错误通常不会导致页面 500 报错,但会表现为登录失效、跳转丢失会话等隐蔽症状。