cookie的SameSite属性

2021.3.22 星期一

Cookie 的 SameSite 属性

Lax模式问题解决

chrome升级到80版本之后 cookie的SameSite属性默认值由None变为Lax,
该问题的讨论可参考:https://github.com/google/google-api-javascript-client/issues/561

在Lax模式下,以下类型请求将受影响:

解决方法1:
下面的设置无效。
Set-Cookie: widget_session=abc123; SameSite=None
下面的设置有效。
Set-Cookie: widget_session=abc123; SameSite=None; Secure

解决方法2:
两个跨域的网站部署到一起

解决问题3:
谷歌浏览器里面:
chrome://flags/
SameSite by default cookies这个参数设置成disabled

解决方法4
修改应用服务器方式
1.tomcat:
首先你需要在httpd.conf文件中开启mod_header模块
LoadModule headers_module modules/mod_headers.so
你打开它以后并不能生效,所以我们还要重写Set-Cookie的头信息,其他的方法我们已经尝试并不可行,目前只有这一种方法可行

2.nginx
在 nginx 的 location 中配置
proxy_cookie_path / “/; httponly; secure; SameSite=None”;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server {
listen 443 ssl http2;
server_name www.cat73.org;

ssl_certificate /etc/letsencrypt/live/cat73.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cat73.org/privkey.pem;

ssl_trusted_certificate /etc/letsencrypt/live/cat73.org/chain.pem;

add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options SAMEORIGIN;
add_header Strict-Transport-Security "max-age=15768000";

location / {
root /var/www/html;
}

location /api {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 在这里设置
proxy_cookie_path / "/; httponly; secure; SameSite=Lax";
}
}

Cookie 的 SameSite 属性
2.1 Strict
Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。
换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。

2.2 Lax
Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 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 不发送

2.3 None
Chrome 计划将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。
不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

CSRF 攻击

Cookie 往往用来存储用户的身份信息,恶意网站可以设法伪造带有正确 Cookie 的 HTTP 请求,这就是 CSRF 攻击。

例来说,用户登陆了银行网站your-bank.com,银行服务器发来了一个 Cookie。
用户后来又访问了恶意网站malicious.com,上面有一个表单。
用户一旦被诱骗发送这个表单,银行网站就会收到带有正确 Cookie 的请求。为了防止这种攻击,表单一般都带有一个随机 token,告诉服务器这是真实请求。

这种第三方网站引导发出的 Cookie,就称为第三方 Cookie。它除了用于 CSRF 攻击,还可以用于用户追踪。
比如,Facebook 在第三方网站插入一张看不见的图片。

<img src="facebook.com" style="visibility:hidden;">
浏览器加载上面代码时,就会向 Facebook 发出带有 Cookie 的请求,从而 Facebook 就会知道你是谁,访问了什么网站。

跨域资源共享 CORS

跨域资源共享 CORS 详解
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
一、简介
二、两种请求
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
(1) 请求方法是以下三种方法之一:
HEAD,GET,POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

三、简单请求

3.1 基本流程
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。
浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。
注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

服务器返回的响应,会多出几个头信息字段。
(1)Access-Control-Allow-Origin
(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
(3)Access-Control-Expose-Headers

3.2 withCredentials 属性
开发者必须在AJAX请求中打开withCredentials属性。
xhr.withCredentials = true;

四、非简单请求

4.1 预检请求
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。

除了Origin字段,”预检”请求的头信息包括两个特殊字段。
(1)Access-Control-Request-Method

(2)Access-Control-Request-Headers

4.2 预检请求的回应

如果服务器否定了”预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。
这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

服务器回应的其他CORS相关字段如下。
(4)Access-Control-Max-Age

fetch的mode

fetch的mode配置项有3个值,如下:

same-origin:该模式是不允许跨域的,它需要遵守同源策略,否则浏览器会返回一个error告知不能跨域;其对应的response type为basic。
cors: 该模式支持跨域请求,顾名思义它是以CORS的形式跨域;当然该模式也可以同域请求不需要后端额外的CORS支持;其对应的response type为cors。
no-cors: 该模式用于跨域请求但是服务器不带CORS响应头,也就是服务端不支持CORS;这也是fetch的特殊跨域请求方式;其对应的response type为opaque。

注意: cors 支持 三种content-type 不支持 application/json
application/x-www-form-urlencoded
multipart/form-data
text/plain

通知浏览器更新或者设置cookie
Set-cookie:name=name;expires=date;path=path;domain=domain;secure name=name: 需要设置cookie的值(name不能使用“;”和”,”号),有多个name值时用”;”分隔例如:name1=name1; name2=name2;name3=name3。

expires=date: cookie的有效期限,格式: expires=”Wdy,DD-Mon-YYYY HH:MM:SS”
path=path: 设置cookie支持的路径,如果path是一个路径,则cookie对这个目录下的所有文件及子目录生效,例如:path=”/cgi-bin/“,如 果path是一个文件,则cookie指对这个文件生效,例如:path=”/cgi-bin/cookie.cgi”。
domain=domain: 对cookie生效的域名,例如:domain=”gzdzw.51.net”
secure: 如果给出此标志,表示cookie只能通过SSL协议的https服务器来传递。
cookie的接收是通过设置环境变量HTTP_COOKIE来实现的,CGI程序可以通过检索该变量获取cookie信息。

### 不唯一
服务器生成Cookie,会产生一个Set-Cookie报头,放在HTTP报文中一起回传客户端。
不是唯一,一个Set-Cookie报头对应一条Cookie。
浏览器一般允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。

knowledge is no pay,reward is kindness
0%