产品的安全性,是第一位的。在之前工作中,坏人曾使用CSRF(cross-site request forgery)进行过恶意攻击,今天来聊一下CSRF攻击及防御。顺便提醒大家:
1. 遇到不明链接,不要随意乱点。
2. 在登录银行网站后,要记得退出登录,而不是直接关闭网页。
A的正常转账操作
A登录银行账户后,给B转账100元,银行后台会校验登录态skey, 最后转账成功,http请求如下(本文全部用http来描述):
http://www.bank.com/transfer.php?from=A&money=100&to=B
C的恶意操作,失败
C心里痒痒的,想盗取A的钱,于是C在自己的浏览器中执行:
http://www.bank.com/transfer.php?from=A&money=100&to=C
这个请求会失败,因为C的浏览器中,没有A的登录态skey, 所以无法把A的钱转出来:
C让A点击C的恶意链接,得逞
C无法执行http请求进行转账,那么C就开始动歪心思了,C准备让A在A自己的浏览器中执行:
http://www.bank.com/transfer.php?from=A&money=100&to=C
此时,如果A点击链接,会携带A的登录态skey, 于是C就盗走了A的100元:
这里的问题就在于,A自己点击了C的恶意链接,导致钱被盗。可是,在很多情况下,A并不会那么傻,并不会随意点击链接。
A虽不傻,但A可能很贪。比如C可以做一个抽奖网页、红包网页或者色情网页,诱导A去点击:
以抽奖网页为例,C抽奖网页的html代码如下:
<html>
<body>
<form method="get" action="http://www.bank.com/transfer.php">
<input type="hidden" name="from" value="A">
<input type="hidden" name="money" value="100">
<input type="hidden" name="to" value="C">
<input type="submit" value="抽奖">
</form>
</body>
当A看到一个精妙绝伦的抽奖网页后,内心就有贪念了,于是点击抽奖按钮,触发了C隐藏的转账操作,相当于A无意中在自己的浏览器上执行了如下http请求:
http://www.bank.com/transfer.php?from=A&money=100&to=C
而A的浏览器又具备登录态skey,所以,A的100元钱就被C偷走了。
这就是所谓的CSRF跨站请求伪造: 坏人C伪造了转账请求,A在不知情的情况下,完成了转账操作。
防御方法一:校验refer
当A正常给B转账100元时,http请求的refer是银行网页。但是,当A不小心执行了C的恶意请求时,http请求的refer是C的抽奖网页。所以,在银行后台,可以通过校验http的refer判断并防御。
防御方法二:校验token
可以在http请求参数中增加token字段,最简单的方式时候是直接把登录态skey的值赋值给token, 这样银行后台对token进行校验,要求等于skey, 才认为合法。所以,正常的转账请求是(假设skey=asdf):
http://www.bank.com/transfer.php?from=A&money=100&to=B&token=asdf
然后,在银行后台发现skey=asdf, 而token=asdf, 两者相等,自然转账成功。
此时,C就为难了,C没法知道A浏览器上的登录态skey的具体值, 所以C根本不知道在token上要填写什么值,假设C随便填一个abc, 那么实际上,A执行C的恶意请求是:
http://www.bank.com/transfer.php?from=A&money=100&to=C&token=abc
然后,银行后台发现skey=asdf, 而token=abc, token和skey的值不相等,自然拒绝。
可见,利用token可以防御CSRF攻击。值得一提的是,token的构造,不一定要使用skey本身的值,也可以考虑对其进行哈希,这样更安全。
在实际场景中,通常结合方法一和方法二来防御CSRF攻击。最后,还是文章开头那个建议:
1. 遇到不明链接,不要随意乱点。
2. 在登录银行网站后,要记得退出登录,而不是直接关闭网页。