CSRF与SameSite

什么是Cookie

为了解释CSRF与SameSite的成因、关系与历史,我们首先需要对Cookie有一个基础的了解。

我们知道,HTTP请求本身是无状态的,正常来说,服务端收到请求后并不知道请求者是谁;

所以为了记录用户的标识信息,来提供更好更便捷的网络服务,Cookie应运而生。

就好像我们使用ATM服务(HTTP服务)一样,没有插入银行卡(Cookie)之前,机器并不知道面前的人是谁,有多少余额,甚至不让你使用大部分的功能;但是当你插入之前银行发售(SetCookie)给你的银行卡(Cookie)之后,ATM服务(HTTP服务)就能够认识你,并提供针对你的服务。

如图,可以看到大家[耳]熟能详的Cookie数据流过程。

  1. 首先,用户在浏览器中请求目标网站,请求内容是自己的身份信息(比如登录或者注册)。
  2. 服务收到用户信息后,会在这个HTTP请求的返回中给浏览器SetCookie的指令,并带上一串能够代表这个用户的id(银行卡号),浏览器收到SetCookie后,会将这个网站id在浏览器中进行存储。
  3. 当用户再次请求这个网站的其他HTTP服务时(比如获取购买记录),浏览器会自动检测本地Cookie中的id并自动添加到请求内容中。
  4. 这样,HTTP服务端收到这个请求的同时也会收到Cookie信息,通过查询后台数据便可得知这个用户的信息,返回针对这个用户的数据。

所以,Cookie是浏览器用来存储用户在各个网站的用户标识信息,是一系列小而碎的数据块(银行卡号),就好像碎饼干(Cookie)一样。

Cookie的生效范围

继续用上面银行卡的例子。虽然是一个人,但是我们知道中国银行的ATM理论上只能使用中国银行发售的银行卡,招商银行的ATM只能使用招商银行发售的银行卡。(先不考虑银联,VISA这种情况)。

Cookie也是一样,一个网站签发的Cookie只能由这个网站(domain)使用。

如图,假设用户在访问example.com时,浏览器存储了一个Cookie,那么用户在访问相同domain(example.com)的HTTP服务时,浏览器都会带上这个Cookie(比如www.example.com, demo.example.com, abc.example.com)。反之,如果访问*.xyz.com时,浏览器就不会带上任何example.com的Cookie。

Cookie的漏洞

在早期(2016年前),浏览器对Cookie的使用校验很简单也很容易理解:

浏览器在请求一个网站时,只要浏览器存储了适用于这个网站的Cookie,就会带上它发起请求

看上去没有毛病,Cookie本来就是干这个的。

但是这个规则只限制了浏览器发起请求时只能携带与目标网站匹配的Cookie,并没有限制在哪个网站发起的请求才可以携带Cookie,即:

在网站A网页中,如果有一个按钮是向网站B发起了一个请求,虽然B网站和A一点关系都没有,但仍然会带上你在B网站的Cookie将请求发出去

比如,恶意A网站里面有一个按钮,按钮名字叫做“点我试试”,但按钮背后的功能是:向淘宝发起购买退烧药的支付请求;如果你在浏览器中登录过淘宝且有余额,那么你在A网站点击这个按钮会,就会真的完成一次购买退烧药的操作。

很明显,这和用户的原始意图是完全背离的,这就是CSRF攻击。

CSRF

跨站请求伪造(英语:Cross-site request forgery),是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。

上面“点我试试”的恶意按钮,就是CSRF攻击的一种:虽然点击行为是用户发起的,但背后的行为却不是用户的本意,也不是被请求网站(上例的淘宝)希望发生的。

问题的根源在于:浏览器允许网站A向和自己无关的网站B发起请求(并携带网站B的Cookie)。

发现了这个问题后,很快在2016年就引入了Cookie的SameSite属性,禁止跨站请求携带Cookie,从而确保了能够携带Cookie的请求一定是用户在浏览器自己的网站期间发出来的。

Cookie的SameSite属性

2016年开始引入了Cookie的SameSite属性,确保携带Cookie发起请求的网站和请求目标的服务是同站(SameSite)的,如图。

用户首先访问了www.dominio-X.com,这个dominio-X在用户登录过程中存储了Cookie A和Cookie B,其中Cookie A是普通的Cookie没有SameSite属性,Cookie B拥有SameSite属性。

这个之后,用户通过浏览器访问了一个恶意网站www.dominio-Y.com,这个恶意网站会向www.dominio-X.com发送请求,这时可以看到,普通的Cookie A会在用户不知情的情况下被携带一并传送过去,而拥有SameSite的Cookie B浏览器会发现虽然Cookie B是属于dominio-X的,但是和发起的网站dominio-Y并不一样,跨站了(Cross Site),此时浏览器就会阻止Cookie B的传输,保护了用户。

SameSite的取值范围

1
2
3
4
5
6
7
8
9
10
11
12
- Strict
完全禁止跨站传递Cookie,比如A网站通过超链接跳转B网站也不行,必须用户手动输入这个B网站浏览器才允许使用B网站的Cookie。
过于严格,很少使用。
- Lax
相对宽松(reLax)的规则,大部分情况也不允许跨站传递Cookie,但是对于较为安全的场景:超链接跳转,get类型的Form表单,是允许的。
这个模式是大部分浏览器的SameSite的默认取值(当服务端SetCookie没有制定SameSite时,大部分现代浏览器会默认使用Lax)。
使用Lax已经能够杜绝CSRF攻击。
- None
完全没有限制。
老版本浏览器默认仍然会使用None作为SameSite的默认取值。
大部分现代浏览器默认是Lax。
以及None默认过于危险,如果要使用SameSite=None则浏览器会要求网站服务使用https才行。