CSRF攻击原理讲解
CSRF(Cross Site Request Forger)
跨站请求伪造
CSRF是如何攻击的
这样的,比如你在 http://wwww.aaa.com
网站里面, 你现在登录了
假如,有一个修改密码的接口,需要传一个用户名和新密码就能修改,并且要向后端传cookie
,cookie
校验通过了就进行修改
get请求
http://wwww.aaa.com?username=zhangsan&newPassword=123456
我们这样调用接口就能修改成功
黑客网站 http://wwww.bbb.com
<a href="http://wwww.aaa.com?username=zhangsan&newPassword=123456" target="_blank">
点击看美女
</a>
你现在在浏览黑客网站 http://wwww.bbb.com
的网页
你就看见美女兴奋去点击了,因为刚才我们说了你在 http://wwww.aaa.com
是登录着的,新标签打开了aaa网站,就会去请求 http://wwww.aaa.com?username=zhangsan&newPassword=123456
这个接口,因为现在本来就在aaa网站下的,就不会存在跨越问题,所以就会默认携带cookie去请求。这样就把你的信息给修改了, 这样黑客不知道你的密码,但修改成了新的密码,他就能用这个新的密码去登录你的aaa网站了,你的信息就都被盗取了
post请求
我们新打开一个窗口,在地址栏中输入链接,回车,这就是一个get请求
但如果我们修改密码是post提交呢?那黑客怎么做,那就需要用表单了,这样就可以发送的是pos
t请求,点击的时候也会跳转到aaa
网站,也就会携带cookie
<form action="http://wwww.aaa.com" method="post">
<!-- <form action="https://ask.csdn.net/channel/11" method="post"> -->
<input type="text" name="username" value="zhangsan" hidden>
<input type="text" name="newPassword" value="123456" hidden>
<button type="submit">点击查看美女</button>
</form>
我们写一个例子,从我们本地就看见跳转成功了,发送了请求,把cookie
携带上了
是从我们本地 http://127.0.1:5500
跳过去的,可以看见origin
防护措施
1、Token验证
既然浏览器默认会携带cookie, 那我们就使用token来验证,放在请求头里,这样浏览器就不会自动携带了
2、同源检测
既然CSRF大多来自第三方网站,那么我们就直接禁止外域(或者不受信任的域名)对我们发起请求
- Origin Header
- Referer Header
这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。 服务器可以通过解析这两个Header中的域名,确定请求的来源域。
###3、Samesite Cookie属性
Chrome 51开始,浏览器的Cookie新增加了一个SameSite
属性,用来防止CSRF攻击和用户追踪。Samesite有三个可选值,分别为Strict、Lax、None。
Samesite Cookie属性
防止CSRF攻击的办法已经有上面的预防措施。为了从源头上解决这个问题,Google起草了一份草案来改进HTTP协议,那就是为Set-Cookie响应头新增Samesite属性,它用来标明这个 Cookie是个“同站 Cookie”,同站Cookie只能作为第一方Cookie,不能作为第三方Cookie,Samesite 有两个属性值,分别是 Strict 和 Lax,下面分别讲解:
Samesite=Strict
这种称为严格模式,表明这个 Cookie 在任何情况下都不可能作为第三方 Cookie,绝无例外。比如说 b.com 设置了如下 Cookie:
Set-Cookie: foo=1; Samesite=Strict
Set-Cookie: bar=2; Samesite=Lax
Set-Cookie: baz=3
我们在 a.com 下发起对 b.com 的任意请求,foo 这个 Cookie 都不会被包含在 Cookie 请求头中,但 bar 会。举个实际的例子就是,假如淘宝网站用来识别用户登录与否的 Cookie 被设置成了 Samesite=Strict,那么用户从百度搜索页面甚至天猫页面的链接点击进入淘宝后,淘宝都不会是登录状态,因为淘宝的服务器不会接受到那个 Cookie,其它网站发起的对淘宝的任意请求都不会带上那个 Cookie。
Samesite=Lax
这种称为宽松模式,比 Strict 放宽了点限制:假如这个请求是这种请求(改变了当前页面或者打开了新页面)且同时是个GET请求,则这个Cookie可以作为第三方Cookie。比如说 b.com设置了如下Cookie:
Set-Cookie: foo=1; Samesite=Strict
Set-Cookie: bar=2; Samesite=Lax
Set-Cookie: baz=3
当用户从 a.com 点击链接进入 b.com 时,foo 这个 Cookie 不会被包含在 Cookie 请求头中,但 bar 和 baz 会,也就是说用户在不同网站之间通过链接跳转是不受影响了。但假如这个请求是从 a.com 发起的对 b.com 的异步请求,或者页面跳转是通过表单的 post 提交触发的,则bar也不会发送。
生成Token放到Cookie中并且设置Cookie的Samesite,Java代码如下:
private void addTokenCookieAndHeader(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
//生成token
String sToken = this.generateToken();
//手动添加Cookie实现支持“Samesite=strict”
//Cookie添加双重验证
String CookieSpec = String.format("%s=%s; Path=%s; HttpOnly; Samesite=Strict", this.determineCookieName(httpRequest), sToken, httpRequest.getRequestURI());
httpResponse.addHeader("Set-Cookie", CookieSpec);
httpResponse.setHeader(CSRF_TOKEN_NAME, token);
}
代码源自OWASP Cross-Site_Request_Forgery #Implementation example
我们应该如何使用SamesiteCookie
如果SamesiteCookie被设置为Strict,浏览器在任何跨域请求中都不会携带Cookie,新标签重新打开也不携带,所以说CSRF攻击基本没有机会。
但是跳转子域名或者是新标签重新打开刚登陆的网站,之前的Cookie都不会存在。尤其是有登录的网站,那么我们新打开一个标签进入,或者跳转到子域名的网站,都需要重新登录。对于用户来讲,可能体验不会很好。
如果SamesiteCookie被设置为Lax,那么其他网站通过页面跳转过来的时候可以使用Cookie,可以保障外域连接打开页面时用户的登录状态。但相应的,其安全性也比较低。
另外一个问题是Samesite的兼容性不是很好,现阶段除了从新版Chrome和Firefox支持以外,Safari以及iOS Safari都还不支持,现阶段看来暂时还不能普及。
而且,SamesiteCookie目前有一个致命的缺陷:不支持子域。例如,种在topic.a.com下的Cookie,并不能使用a.com下种植的SamesiteCookie。这就导致了当我们网站有多个子域名时,不能使用SamesiteCookie在主域名存储用户登录信息。每个子域名都需要用户重新登录一次。
总之,SamesiteCookie是一个可能替代同源验证的方案,但目前还并不成熟,其应用场景有待观望。
参考:
前端安全系列(二):如何防止CSRF攻击?