这是我在知乎的一个回答。原提问是如何在单页应用下进行 XSRF 防御。html
XSRF(CSRF) 攻击的原理是什么?就是攻击者能猜想出全部的须要提交的内容以及类型,因此全部的解决方案共同出发点就是加一个攻击者也不知道随机值发送给后端验证就能够防范。前端
有不少解决方案,cookie-session,很不友好的全部表单都得填写验证码,还有一种不多人知道 JSON Web Token。ios
验证码(图形或者手机)这种就不说了吧,这个在互联网场景中由于用户体验缘由几乎没有应用的。ajax
首先要知道直接让后端验证 cookie 是否存在正确是不可取的,由于全部请求都会自动附带请求所在域的 cookie,固然只验证 http referrer 也是不靠谱的。axios
正确的方式是当用户进行登陆请求的时候,这时候后端应该把包含 xsrf 字段的 cookie 保存在 session 中而且返还给前端,前端须要获取到 cookie 中的值而且能放入 ajax 请求体或请求头中,后端把这个值与 session 中的相应值进行判断就能够了,根据跨域不可访问不一样域的 cookie ,攻击者也很难猜想出 xsrf 的值,那么这样就防范了 xsrf 攻击。后端
因此这里对 xsrf cookie 不能设置 httpOnly(固然就会有 XSS 问题,后面会提),同时提一句因此的 Token 必须得让后端设置 expire 过时时间。跨域
这个 axios 就提供了这个功能,只要设置约定好 xsrf cookie字段名就能够了,axios 获取到值后默认是放入 request header 中,这也是业界最流行的方式。缓存
若是不是单页应用都是后端在表单中加入一个隐藏的表单域。安全
<input type="hidden" name="_token" value="lAfHB..">
固然还有JWT,这个主要应用场景是 app,由于 app 一般没有 Cookie,固然也有应用到 Web 中的,要讲这个就有点多了,和上述也差很少。服务器
简单说,JWT 就是服务端和客户端约定好一个Token格式,最后用密钥进行签名 base64 编码后放入请求头便可,客户端存放这个签名的内容一般会放在 localstorage 中,也有放在 cookie 中的。JWT应用了哈希签名的密码学技术,相比 cookie-session 的方式就是服务端能够不用(在内存或者缓存)存放 session,能节省存储资源,不过同时服务器须要经过计算来验证也浪费了计算资源。详细的说明能够参考:讲真,别再使用JWT了!
现有的产品为了更安全还须要考虑 XSS 攻击,这个就是有些恶意脚本或者插件不存在跨域问题,因此能获取到 cookie 和 localstorage 的值。
很安全的方式就是把 XSRF Token 加入到 JWT 中,而且把 JWT 存放在设置 httpOnly 的 cookie 中,而后单独把 XSRF Token 设置在 httpOnly=false 的 cookie 中,前端请求时,须要获取 XSRF Token 并放入请求头(RequestHeader)。服务器端能够直接验证JWT中XSRF的值和XSRF的值便可。由于用了哈希密钥签名的技术,这样就能够防止篡改内容。
这样的安全防御就能抵御全部的 XSRF 攻击了。