1. 验证码
CSRF攻击用户在不知情的情况下构造了网络请求,而验证码则强制用户必须与应用进行交互,才能完成最终的请求。
2. Referer校验
Referer校验在互联网中最常见的应用就是“防止图片盗链”。同理,Referer校验也可以用于检查请求是否来自合法的“源”。
3. Cookie的SameSite属性
Cookie的SameSite属性,可以控制Cookie在跨站点请求中是否生效。
4.Anti-CSRF Token
(1)Token原理
把参数加密或者使用签名,让攻击者无法生成参数值
例如:一个删除操作的URL是:
http://host/path/delete?username=abc&item=123
把其中的username参数改成哈希值:
http://host/path/delete?username=md5(salt+abc)&item=123
这样在攻击者不知道salt的情况下,是无法构造出这个URL的,因此也就无法从CSRF攻击。
对于服务器来说,可以从Session或Cookie中获取“username=abc”的值,再结合salt对整个请求进行验证,正常请求会被认为是合法的。
但是这个方法也存在问题:
①、加密或签名后的URL将变得非常难读,对用户非常不友好。
②、如果加密的参数每次都会变,则某些URL将无法再被用户收藏。
③、普通的参数如果被加密或哈希,将会给数据分析工作带来很大的困扰,因为数据分析工程常常需要参数的明文。
(2)Anti-CSRF Token
URL保持原参数不变,新增一个参数Token,这个Token的值是随机的。
http://host/path/delete?username=abc&item=123&token=[random(seed)]
Token的值需要足够随机,必须使用足够安全的随机数生成算法等。
Token也需要被放到表单中,在提交请求时,服务器只需验证表单中的Token与用户Session(或Cookie)中的Token是否一致。
如果一致,就认为是合法请求,不一致有一个为空,就认为不合法。
(3)在HTTP头中插入Token字段
JavaScript代码发起请求时虽然也可以往POST数据中添加一个Token,但是这样的话,在代码中每次构造POST数据时都需要往里面插入Token。所以可以在HTTP头中插入Token字段:

可以在渲染HTML页面时,将Token放在<meta>标签中,JavaScript代码要使用时在读取其内(如上面的代码示例),或者读取Cookie中的Token也行。
(4)注意事项
在使用Anti-CSRF Token的注意事项:
①、用来防御CSRF攻击的Token,是根据“不可预测性”原则设计的方案,所以Token的生成一定要足够随机化,需要使用安全的随机数生成器生成Token。
②、这个Token的目的不是为了防止重复提交。
③、有一些其他的途径可能导致Token泄露,例如:XSS漏洞和一些跨域漏洞(JSONP跨域信息泄露等)。
