本文演示 Demo 的代码地址: CSRF
CSRF是什么?
CSRF(Cross Site Request Forgery),翻译成中文就是跨站点请求伪造。
简单地说,CSRF就是利用了我们的登录状态或者授权状态(请注意“利用”,并没有窃取到),然后做一些损害我们自身利益的事情。
在本文的 demo 中会简单演示一下 CSRF 攻击:
在启动服务并登录成功之后,通过对浏览器进行调试,在请求列表我们可以看到所有文章的id
对文章执行删除操作,发现其实是执行了一个下面这样的请求
http://localhost:3000/articles/delete/5a2398eb4d39c72e1db2006e
我们新打开一个浏览器窗口, 在获取到的id列表中取一个替换上面 url 中的id,执行请求, 页面显示
返回原页面,刷新后,发现又有一篇文章被删除了。
这就是一个 CSRF 攻击的过程
GET & POST
如 demo 中演示,我们是通过 GET 请求进行 CSRF 攻击的,那我们换成 POST 请求是不是就可以避免 CSRF 攻击了呢?
其实并不能,我们可以通过 form 表单伪造一个 POST 请求来进行 CSRF 攻击。
在浏览器中打开 test.html
html 代码如下:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>CSRF</title>
</head>
<body>
<form action="http://localhost:3000/articles/delete" method="POST">
<input type="hidden" name="id" value="5a23ca3a24f5d73343759637">
<input type="submit" value="点击中大奖">
</form>
</body>
</html>
修改 test.html,取一个获取到的文章 id,替换表单中 name 为 id 的 value,此时点击按钮时,发现同样可以成功的删除文章。由此可见,POST也能造成 CSRF 攻击。如此一来,不管哪种访问方式都可能受到攻击。所以,这并不是GET和POST谁更安全的问题,POST只是提高了攻击门槛和成本。
CSRF 的防御
- 验证码
验证码被认为是对抗 CSRF 攻击最简洁而有效的防御方法。
CSRF 攻击的过程,往往是在用户不知情的情况下构成了网络请求。而验证码,则强制用户必须与用户进行交互,才能完成最终请求。因此在通常情况下,验证码能够很好的遏制 CSRF 攻击。但是验证码并非万能,出于用户体验考虑,网站不能给所有的操作都加上验证码,因此,验证码只能作为防御 CSRF 的一种辅助手段,而不能作为最主要的解决方案。 - Anti CSRF Token
CSRF 为什么能够攻击成功? 其本质原因是服务器无法识别你的来源是否可靠。而操作的所有参数都是可以被攻击者猜测到的。攻击者只要预测出 URL 的所有参数与参数值,就能成功的构造一个伪造的请求。
出于这个原因,我们可以想到一个解决方案:把参数进行加密。这样攻击者不知道如何解密的情况下是无法伪造请求的。但是这个方法也存在一些问题。加密后的 URL 将变得非常难读,对用户非常不友好。因此我们需要一个更加通用的解决方案。这个方案就是使用 Anti CSRF Token。
在服务端生成一个随机的 Token,放在用户的Session中,或者浏览器的 Cookie 中,提交请求时将 Token 加入到HTTP请求参数中,服务器拦截请求,查看发送的 Token 和服务端的是否一致,若一致,则允许请求;若不一致,则拒绝请求。而 Token 之所以能够拦截,就是因为它是 CSRF 攻击过程中几乎不可能伪造的东西。
最后我们再使用 Token 时,一定要注意 Token 的随机性和保密性,不要把 Token 暴露在 GET 请求中哦。
参考
《白帽子讲Web安全》