很多厂在面试的时候,都喜欢问一下关于web安全的问题,比如接下来要说的这个,什么是CSRF以及防范措施有哪些?这文章会带你搞懂CSRF。
什么是CSRF?
(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式。
我们通过一个例子来了解它:
小明登陆了一个银行网站 www.bank.com
,银行服务器发来了一个cookie,
Set-Cookie:id=a3fWa;
后来小明又访问了一个恶意网站 www.hacker.com
, 这个恶意网站中有一个表单
<form action='www.bank.com/transfer' method='POST'>
...
</form>
小明无意间触发了这个表单,银行服务器会收到带有正确cookie的请求,然后银行服务器会执行自己定义的操作transfer
,这个时候就有可能把小明账户的钱给转走。
CSRF特点
- 攻击一般发生在第三方网站,而不是被攻击网站;
- 攻击利用用户在被攻击网站的登陆凭证(cookie),冒充受害者提交操作,而不是直接窃取数据;
- 整个过程,攻击者并不能获取到登录凭证,而是冒用;
- 跨站请求可以用各种方式:img图片的src、a标签、form表单提交等等;
你说可怕不可怕?当然可怕,那需要怎么防止CSRF攻击呢?你可能会说,用户不点击进入恶意网站不就行了。这当然可以,但是你不能保证每个人都不去点击恶意网站,所以我们还是要做自动防御,就算用户访问了恶意网站,也要保证我们的网站不会收到攻击。
防御措施
我们知道,CSRF一般发生在第三方网站,而且攻击者只是冒用登录凭证而不是获取登录凭证数据,所以我们制订以下防范策略:
阻止不明外部域名的访问
- 同源检测
- Samesite Cookie
提交Form表单时,添加本域才能获取的验证信息
- CSRF token
1. 同源检测
Cookie的同源和浏览器的同源策略有所区别:
* 浏览器同源策略:协议、域名和端口都相同即同源;
* Cookie同源策略:域名相同即同源;
在HTTP协议中,每个异步请求都会携带两个header,用来标记来源域名:
* Origin Header
* Referer Header
这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端修改,服务器接收到后可以根据这两个Header确定来源的域名;
特殊情况: 如果Origin和Referer都不存在,建议直接进行阻止,特别是如果您没有使用随机CSRF Token(参考下方)作为第二次检查。
另外,CSRF大多数情况下来自第三方域名,但并不能排除本域发起。如果攻击者有权限在本域发布评论(含链接、图片等),那么它可以直接在本域发起攻击,这种情况下同源策略无法达到防护的作用。
综上所述:同源验证是一个相对简单的防范方法,能够防范绝大多数的CSRF攻击。但这并不是万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,我们就要对关键的接口做额外的防护措施。
2. Samesite Cookie属性
Chrome 51版本 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击。
Cookie的Samesite属性用来限制第三方Cookie, 从而减少安全风险,它有三个值:
Set-Cookie: SameSite = Strict;
Set-Cookie: SameSite = Lax;
Set-Cookie: SameSite = None;
Strict: 最为严格,完全禁止第三方Cookie, 跨站点时,任何情况都不发送Cookie;
Lax: 限制稍微宽松,大多数情况下时不发送第三方Cookie的,除了a链接、预加载请求和GET表单;
None: 关闭SameSite
属性,但必须同时设置Secure
属性,如下:
Set-Cookie: SameSite = None // 无效
Set-Cookie: SameSite = None; Secure // 有效
设置了Strict
或Lax
,基本就能阻止CSRF
攻击,前提是浏览器支持SameSite
属性。
3.CSRF token
CSRF攻击之所以能够成功是因为服务器把攻击者携带的Cookie当成了正常的用户请求,那么我们可以要求所有用户请求都携带一个无法被攻击者劫持的token,每次请求都携带这个token,服务端通过校验请求是否为正确token,可以防止CSRF攻击。
CSRF token的防护策略分为三步:
- 将token输出到页面
首先,用户打开页面的时候,服务器需要给这个用户生成一个Token,该Token通过加密算法对数据进行加密,一般Token都包括随机字符串和时间戳的组合,显然在提交时Token不能再放在Cookie中了,否则又会被攻击者冒用。 请求中携带token
对于GET请求,将token附在请求地址之后,如:http://url?token=tokenValue
对于POST请求,要在Form表单后面加上<input type=”hidden” name=”token” value=”tokenvalue”/>
- 服务端验证token是否正确
服务端拿到客户端给的token后,先解密token,再比对随机字符串是否一致、时间是否有效,如果字符串对比一致且在有效期内,则说明token正确。
总结
简单总结一下上文的CSRF攻击的防护策略:
- 自动防护策略:同源检测(
Origin
和Referer
验证); - 主动防护策略:
token
验证以及配合SameSite
设置; - 保护页面的幂等性,不要再GET请求中做用户操作
为了更好的防御CSRF,最佳实践应该是结合上面总结的防御措施方式中的优缺点来综合考虑,结合当前Web应用程序自身的情况做合适的选择,才能更好的预防CSRF的发生。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。