最近项目中遇到一个问题,就是a.com域名下使用b.com域名的jsonp获取数据,竟然无法把b.com的cookie上发。
一)发现问题
1)确认浏览器版本,chrome的83.0.4103.116版本,无法上发跨域cookie
2)测试其他浏览器版本,QQ浏览器10.6(Chromium70.0.3538.25),可以正常上发跨域cookie
3)查找差异性,因为是cookie问题,我们服务端写cookie是使用php的setcookie方法,所以我们查找php.net官网setcookie方法,我们发现了一个设置值,就是cookie的samesite这个属性。见后面参考1。
二)什么是samesite
samesite最早出自草案:https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02。
Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击和用户追踪。以前samesite默认为None。
chrome升级到80后,把samesite默认值设为lax,导致了jsonp传递cookie的问题。
我们可以通过chrome的地址访问:chrome://flags/
查找samesiite,就可以找到实验室中的几个选项,只要禁用第一个选项,就可以上发cookie了。但是有没有其他不禁用的方法,因为这个版本默认就开启了,不可能让用户来手动设置,所以我们需要了解一下这是个什么东西。
Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。
它可以设置三个值:Strict,Lax和None。
1)Strict值,严格,完全禁止第三方cookie,跨站时,任何情况都不发送cookie。
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
2) Lax,稍微宽松,大多数情况也不发送第三方cookie,但是导航到目标地址的Get请求除外。
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。
请求类型 | 示例 | 正常情况 | Lax |
链接 | <a href="..."></a> | 发送 Cookie | 发送 Cookie |
预加载 | <link rel="prerender" href="..."/> | 发送 Cookie | 发送 Cookie |
GET 表单 | <form method="GET" action="..."> | 发送 Cookie | 发送 Cookie |
POST 表单 | <form method="POST" action="..."> | 发送 Cookie | 不发送 |
iframe | <iframe src="..."></iframe> | 发送 Cookie | 不发送 |
AJAX | $.get("...") | 发送 Cookie | 不发送 |
Image | <img src="..."> | 发送 Cookie | 不发送 |
设置了Strict或Lax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。
3)None,chrome默认lax,但是我们网站可以显式关闭SameSite属性,设置为None既可。但是前提必须设置Secure属性为true,否则设置无效。
//无效 Set-Cookie: widget_session=abc123; SameSite=None //有效 Set-Cookie: widget_session=abc123; SameSite=None; Secure
三)php中设置带SameSite的cookie
1)服务器通用配置
1.1)apache通用配置
Header always edit Set-Cookie (.*) "$1; SameSite=Lax"
1.2) nginx通用配置
location / { # your usual config ... # hack, set all cookies to secure, httponly and samesite (strict or lax) proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict"; }
2)PHP >= v7.3,可以直接设置samesite
setcookie($name, $value, [ 'expires' => time() + 86400, 'path' => '/', 'domain' => 'domain.com', 'secure' => true, 'httponly' => true, 'samesite' => 'None', ]);
3)PHP <v7.3,无法直接设置samesite
//通过header设置 header("Set-Cookie: key=value; path=/; domain=example.org; HttpOnly; SameSite=Lax"); //通过setcookie方法设置,利用path传入"/;samesite=None",这是利用php的一个bug,不会对path里面的“;”进行处理 setcookie('cookie-name', '1', 0, '/; samesite=strict');
四)参考
1)php设置cookie方法:
https://www.php.net/manual/en/function.setcookie.php
2)php中setcookie的bug可以查看:
https://github.com/php/php-src/commit/5cb825df7251aeb28b297f071c35b227a3949f01
3)Cookies:HTTP状态管理机制草案05:
https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-05
4)samesite兼容内容:
https://www.chromium.org/updates/same-site/incompatible-clients