这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
- 理解csrf的基本概念
- 基本csrf的攻击原理和方式
- csrf 的预防手段
CSRF一般指跨站请求伪造。跨站请求伪造
与XSS不同的是,CSRF是利用了用户的登录态,XSS不需要用户具有登录态。
从用信任角度可以这样区分:
- xss:用户过分信任网站,放任来自浏览器地址栏代表的那个网站代码在自己本地任意执行。如果没有浏览器的安全机制限制,xss代码可以在用户浏览器为所欲为;
- csrf:网站过分信任用户,放任来自所谓通过访问控制机制的代表合法用户的请求执行网站的某个特定功能。
1. csrf攻击原理
- 首先用户登录某个网站,并保留了登录凭证(Cookie)
- 用xss方式植入一段请求,或者使用其他方式植入一段请求,或者登录了攻击者提供的引诱危险站点发生了请求(这就是伪造请求),利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的
- 服务器接受到请求,进行响应处理,其处理结果就是攻击者想要的结果
2. csrf例子分析
2.1 使用xss方式植入伪造请求
- 用户登录目标某钱财交易网站,并保留了登录凭证(Cookie),其提现转账请求就是
http://assert.example.com/withdraw?account=xxx&amount=xx&for=xxx - 网站没有做好关于图片的的XSS防御,植入了这样一段代码
<img src="http://assert.example.com/withdraw?account=xiaoming&amount=1000000&for=mallory">,其实植入链接也是可以的,例如<a href="http://assert.example.com/withdraw?account=xiaoming&amount=1000000&for=mallory" taget="_self">充一块,得1万,稳赚不赔<a/> - 当用户登录访问到被这样攻击的页面时,钱就转到了小明身上了
2.2 用户登录期间访问诱导站点
- 用户登录目标某钱财交易网站,并保留了登录凭证(Cookie)
- 用户访问了黑客站点,黑客站点在他的页面隐藏了一个转账的表单
<form name="form" method="POST" action="http://assert.example.com/withdraw" target="hidden"> <input type="hidden" name="account" value="xiaoming"/> <input type="hidden" name="amount" value="10000000"/> <input type="hidden" name="for" value="mallory"/> </form> <script> const iframe = document.createElement('iframe'); const form = document.querySelector('form'); iframe.name = 'hidden'; iframe.style.display = 'none'; form.style.display = 'none'; document.body.appendChild(iframe); setTimeout(()=>{ form.submit(); },2000) </script>
这段代码就是构造了一个请求表单,利用表单form的target能够提交给iframe,就创建了一个视觉隐藏的iframe目标,这样表单提交就不会刷新,然后将请求提交给目标服务器,由于用户现在是保持登录态的,此请求很可能被认为是合法请求
- 请求提交,攻击目的完成,钱进入了小明的口袋
3. csrf的攻击类型
从上面可以分析出,csrf可以在本域进行(依赖XSS)也可以跨域进行,通常选择跨域进行,这样方便攻击者掌控。从请求方式,有POST类型的csrf和GET类型的csrf,链接型的csrf
4. csrf的特点
- 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
- 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。
- GET类型请求
Header的MIME类型大概率为图片,而实际返回Header的MIME类型为Text、JSON、HTML。
5. 预防针
5.1 同源检测
使用Referer Header确定来源域名,因为Referer也能被篡改,所以不建议使用,了解即可
5.2 CSRF Token
- 将CSRF Token输出到页面中
- 页面提交的请求携带这个Token
- 服务器验证Token是否正确
5.3 表单提交使用验证码和密码
5.4 请求使用保存在LocalStorage和SessionStorage下的token
这种token的值通常是使用UserID、时间戳和随机数,通过加密的方法生成。这样既可以保证分布式服务的token一致,又能保证token不容易被破解。
只要页面没有XSS漏洞泄露Token,那么接口的CSRF攻击就无法成功
5.5 Samesite 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 会;当用户从 a.com 点击链接进入 b.com 时,foo 这个 Cookie 不会被包含在 Cookie 请求头中,但 bar 和 baz 会,也就是说用户在不同网站之间通过链接跳转是不受影响了。但假如这个请求是从 a.com 发起的对 b.com 的异步请求,或者页面跳转是通过表单的 post 提交触发的,则bar也不会发送。
使用这个存在的问题:
- 如果
SamesiteCookie被设置为Strict,浏览器在任何跨域请求中都不会携带Cookie,新标签重新打开也不携带,所以说CSRF攻击基本没有机会。但是跳转子域名或者是新标签重新打开刚登陆的网站,之前的Cookie都不会存在。尤其是有登录的网站,那么我们新打开一个标签进入,或者跳转到子域名的网站,都需要重新登录。对于用户来讲,可能体验不会很好。这是一个致命的缺陷。 - 如果SamesiteCookie被设置为Lax,那么其他网站通过页面跳转过来的时候可以使用Cookie,可以保障外域连接打开页面时用户的登录状态。但相应的,其安全性也比较低。
- 兼容性不是很好
参考资料: