3、在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。
然而这种方法的局限性非常大。XMLHttpRequest 请求通常用于 Ajax 方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行 CSRF 防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。
4、Chrome浏览器端启用SameSite cookie
下面介绍如何启用SameSite cookie的设置,很简单。
原本的 Cookie 的 header 设置是长这样:
Set-Cookie: session_id=esadfas325
需要在尾部增加 SameSite 就好:
Set-Cookie: session_id=esdfas32e5; SameSite
SameSite 有两种模式,Lax跟Strict模式,默认启用Strict模式,可以自己指定模式:
Set-Cookie: session_id=esdfas32e5; SameSite=StrictSet-Cookie: foo=bar; SameSite=Lax
Strict模式规定 cookie 只允许相同的site使用,不应该在任何的 cross site request 被加上去。即a标签、form表单和XMLHttpRequest提交的内容,只要是提交到不同的site去,就不会带上cookie。
但也存在不便,例如朋友发送过来我已经登陆过的一个页面链接,我点开后,该页面仍然需要重新登录。
有两种处理办法,第一种是与Amazon一样,准备两组不同的cookie,第一组用于维持登录状态不设定SameSite,第二组针对的是一些敏感操作会用到(例如购买、支付、设定账户等)严格设定SameSite。
基于这个思路,就产生了 SameSite 的另一一种模式:Lax模式。
Lax 模式打开了一些限制,例如
<a> <link rel="prerender"> <form method="GET">
这些都会带上cookie。但是 POST 方法 的 form,或是只要是 POST, PUT, DELETE 这些方法,就不会带cookie。
但一定注意将重要的请求方式改成POST,否则GET仍然会被攻击。
PS:该方式目前仅Chrome支持。
后记