简介
Chrome升级到80版本后,默认限制了跨域携带cookie给后端,笔者在使用iframe跨域引用页面时遇到无法传递cookie的问题,需要设置SameSite属性为None(同时需要设置Secure属性才能生效)来确保线上服务正常。但是,普通的Web框架需要升级到最新版本才支持SameSite属性,升级Web框架成本太高,且发现包括360、搜狗当前版本浏览器不兼容SameSite属性导致在加入SameSite后无法传递cookie,所以本文提出一套使用Nginx来解决SameSite问题的办法(需要使用Nginx反向代理站点)。
使用Nginx的proxy_cookie_path功能
proxy_cookie_path功能说明:
Sets a text that should be changed in the path attribute of the “Set-Cookie” header fields of a proxied server response. Suppose a proxied server returned the “Set-Cookie” header field with the attribute “path=/two/some/uri/”. The directive
proxy_cookie_path /two/ /;
will rewrite this attribute to “path=/some/uri/”.
具体配置方法(在location节点下加入,配置后重载Nginx):
如果站点Cookie所在目录在根目录/下,设置如下:
proxy_cookie_path / “/; secure; SameSite=None”;
如果站点Cookie所在目录在abc目录下,设置如下:
proxy_cookie_path /abc/ “/abc/; secure; SameSite=None”;
如果无法确定站点Cookie目录,可使用Chrome开发者工具,监测Network下网络请求,找到Response Headers中set-cookie属性值,该值中有path属性值即为Cookie目录,也即上文要替换的/或者/abc/值。
旧浏览器不兼容SameSite问题
笔者在通过使用proxy_cookie_path后发现一些国产浏览器比如360、搜狗浏览器不兼容SameSite属性,cookie直接无法正常传递了,通过浏览器UA判断其使用的chrome内核为较旧版本,为了兼容这些浏览器,这里需要判断UA来实施proxy_cookie_path命令,具体操作方法:
首先,为了让nginx能判断UA中的chrome版本,笔者采用了Nginx支持的njs脚本,编译Nginx支持njs的方法:
http://nginx.org/en/docs/http/ngx_http_js_module.html 然后,编写njs脚本,文件可以命名为ua.js:
function getChromeVersion(r) {
var ua = r.headersIn["user-agent"];
if(ua){
var flag = /Chrome\/([0-9]+)/.exec(ua);
if(flag && flag.length > 1){
return flag[1];
}
}
return -1;
}
function getCookiePathMagicFlag(r) {
var version = getChromeVersion(r);
if(version != -1 && version < 79){
return "-evil";
}
return "";
}
这里将ua.js文件放到nginx.conf同目录下,在nginx.conf 的 http节点下加入两行:
js_include ua.js;
js_set $cookiePathMagicFlag getCookiePathMagicFlag;
(这里$cookiePathMagicFlag是一个标识符,可以根据这个标识符来决定是否执行proxy_cookie_path的替换,也避免了使用nginx的if。)
最后将上文中的proxy_cookie_path命令语句改为:
proxy_cookie_path /$cookiePathMagicFlag “/; secure; SameSite=None”;
或者
proxy_cookie_path /abc/$cookiePathMagicFlag “/abc/; secure; SameSite=None”;
总结
笔者通过以上配置,测试了包括360、搜狗、火狐、IE、chrome浏览器都可以正常传递cookie了。截至最后测试,360、搜狗最新版本(用了旧的chrome内核)依然未兼容SameSite属性。