什么是CSRF
跨站请求伪造(Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web上执行非本意的操作的攻击方法。
简单来说,就是冒用你的登录信息,以你的名义发送恶意请求。
原理
- 用户A登录了自己常用的网站 www.yinhang.com, 登录成功后,cookie中会包含A的登录信息。
- 骗子 利用广告或者链接等诱导你打开网站 www.jiamao.com。该网站中会利用form表单或者其他方式,向网站 www.yinhang.com 发送请求,网站的接口请求格式一般很容易获取到,例如 www.yinhang.com/api/zhuanzhang?account=A&count=10000&to=pianzi 发送的请求会自动携带上www.yinhang.com的cookie信息,即你的身份验证信息
- 服务器端在收到请求后,检验身份信息是正确的,然后整个攻击就完成了
常见解决方案
referer首部
在request header中,有个referer字段,表明请求的来源,服务端可以通过这个字段判断是否是在合法的网站下发送的请求。
缺陷:Referer的值是由浏览器提供的,不同的浏览器实现不同,无法确保某些浏览器是否有安全漏洞,导致可以自行修改Referer字段
表单 token检测
由服务端生成一个token,返回给前端,在每次发送请求中,在参数中额外参加一个参数,例如 _csrf_token , 服务端每次校验时对比 _csrf_token 与服务端存储的值。
fetch(path, {
...otherParam,
_csrf_token: 'token_value'
});
或者服务端返回的表单页面中隐藏 _csrf_token值
<form method="POST" action="/upload" enctype="multipart/form-data">
<input name="_csrf_token" value="{{由服务端生成}}" style="display: none" />
用户名: <input name="name" />
<button type="submit">提交</button>
</form>
缺陷: 需要手动传递参数值,比较冗余麻烦,额外的参数字段也没有业务意义
header中增加csrf_token
由后端生成csrf_token设置在cookie中, 前端获取到token后设置在header中,可以统一在封装request方法时写入,例如
let csrfToken = Cookies.get('csrfToken');
$.ajaxSetup({
beforeSend: function(xhr, settings) {
xhr.setRequestHeader('x-csrf-token', csrfToken);
}
});
留个思考,csrf一般都是跨网站的,按理应该都会有跨域限制,所以请求是怎么发出去的呢。
猜想1: 网站使用了cors跨域访问,但对域名未加限制
猜想2: 某些浏览器并不能对跨域做良好的限制
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。