CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造。
CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求。
包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…
造成的问题:个人隐私泄露以及财产安全。
如果你的验证信息存储在 cookie 中,你有隐式的状态管理。“已登入”状态由一个 cookie 控制,并且这个 cookie 在每个页面的请求中都会发送。不幸的是,在第三方站点触发的请求中也会发送这个 cookie 。如果你不注意这点,一些人可能会通过社会工程学来诱导你应用的用户在他们不知道的情况下做一些蠢事。
比如你有一个指定的 URL ,当你发送 POST 请求时会删除一个用户的资料(比如 http://example.com/user/delete 。如果一个攻击者现在创造一个页面来用 JavaScript 发送这个 post 请求,他们只是诱骗一些用户加载那个页面,而他们的资料最终会被删除。
CSRF攻击示意图
想象你在运行 Facebook ,有数以百万计的并发用户,并且某人放出一些小猫图片的链接。当用户访问那个页面欣赏毛茸茸的猫的图片时,他们的资料就被删除。
防止 CSRF 攻击
你怎样才能阻止这呢?基本上,对于每个修改服务器上内容的请求,你应该使用一次性令牌,并存储在 cookie 里, 并且 在发送表单数据的同时附上它。 在服务器再次接收数据之后,你要比较两个令牌,并确保它们相等。
步骤
- 在客户端向后端请求界面数据的时候,后端会往响应中的 cookie 中设置 csrf_token 的值
- 在 Form 表单中添加一个隐藏的的字段,值也是 csrf_token
- 在用户点击提交的时候,会带上这两个值向后台发起请求
- 后端接受到请求,以会以下几件事件:
从 cookie中取出 csrf_token
从 表单数据中取出来隐藏的 csrf_token 的值
进行对比
- 如果比较之后两值一样,那么代表是正常的请求,如果没取到或者比较不一样,代表不是正常的请求,不执行下一步操作
在 Flask 项目中解决 CSRF 攻击
在 Flask 中, Flask-wtf 扩展有一套完善的 csrf 防护体系,对于我们开发者来说,使用起来非常简单
在 FlaskForm 中实现校验
设置应用程序的 secret_key
用于加密生成的 csrf_token 的值
app.secret_key = "#此处可以写随机字符串#"
在模板的表单中添加以下代码
<form method="post">
{{ form.csrf_token() }}
{{ form.username.label }} {{ form.username }}<br/>
{{ form.password.label }} {{ form.password }}<br/>
{{ form.password2.label }} {{ form.password2 }}<br/>
{{ form.submit }}
</form>
设置完毕,cookie 中的 csrf_token 不需要我们关心,会自动帮我们设置
单独使用
设置应用程序的 secret_key
用于加密生成的 csrf_token 的值
app.secret_key = "#此处可以写随机字符串#"
导入 flask_wtf.csrf 中的 CSRFProtect 类,进行初始化,并在初始化的时候关联 app
from flask.ext.wtf import CSRFProtect
CSRFProtect(app)
如果模板中有表单,不需要做任何事。与之前一样:
<form method="post">
{{ form.csrf_token }}
...
</form>
但如果模板中没有表单,你仍需要 CSRF 令牌:
<form method="post" action="/">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>
exit(?)