认识CSRF及其在Django中的防护

在阅读某产品的代码时,发现了很多CSRF的使用,而且写法不一样。查了查资料,发现说法不一,实践是检验真理的唯一标准,于是搭个小项目进行验证。在此简单总结,分享给需要的同学。

什么是CSRF

CSRF(Cross-site request forgery),中文名称:跨站请求伪造,是一种对网站的恶意利用。其攻击原理如下图:

Django的解决办法

Django使用中间件(CsrfMiddleware)来进行CSRF防护。具体的原理如下:
1、 修改当前处理的请求,向所有的 POST 表单增添一个隐藏的表单字段,使用名称是 csrfmiddlewaretoken,值为当前会话 ID 加上一个密钥的散列值。如果未设置会话 ID,该中间件将不会修改响应结果,因此对于未使用会话的请求来说性能损失是可以忽略的。
2、 对于所有含会话cookie 集合的传入 POST 请求,它将检查是否存在 csrfmiddlewaretoken 及其是否正确。如果不是的话,用户将会收到一个 403 HTTP 错误。 403 错误页面的内容是检测到了跨域请求伪装,终止请求。
另外要说明的是,为了避免转换非 HTML 请求,中间件在编辑响应结果之前对它的 Content-Type 头标进行检查。只有标记为 text/html 或 application/xml+xhtml 的页面才会被修改。接下来介绍具体使用方法。
POST提交form表单
1、添加中间件
在settings.py MIDDLEWARE_CLASSES中把 ‘django.middleware.csrf.CsrfViewMiddleware’ 中间件加上,加上后即可全局使用csrf防护(默认已经添加);
也可以在视图函数上加 @csrf_protect 进行单view控制,不过这不是推荐的方法,因为这样可能会有遗漏。

注:该中间件必须在 SessionMiddleware 之后执行,因此在列表中 CsrfMiddleware 必须出现在SessionMiddleware 之后。 同时,它也必须在响应被压缩或解压之前对响应结果进行处理,因此CsrfMiddleware必须在GZipMiddleware之后执行。
2、模版中设置
在POST提交的表单中加上{% csrf_token %}

或者和表单的格式保持一致,在Form表单里添加


3、视图函数设置
常用的有3种方法:
(1) 手动生成csrftoken并加到template context:


(2) 使用 RequestContext


(3) 直接使用render


如果不需要校验cookie中的csrf值 ,对应的函数加 @csrf_exempt 装饰器


ajax提交post请求
1、 settings设置同上;
2、 模板中设置
有2种方法:
(1) 在html模板script标签中加(注:不能 js文件中设置)


(2) 设置请求头
使用Cookie插件 https://github.com/js-cookie/js-cookie/


第一种更简单
3、 视图函数设置同上
其它模板引擎(与jinja2结合)
1、 settings及视图函数设置同上;
2、 模板设置
Jinja不能识别 {% csrf_token %},如下设置


或者


3、 视图设置同上

以上内容,欢迎指正。

发表评论