Django 跨站请求伪造(csrf)防御——解决 POST 请求 403 问题

文章目录

    • 背景
    • Django 的跨站请求伪造(csrf)防御
    • 取消 csrf 防御
    • 对某个特定请求开启 csrf 防御
    • 设置 csrf token
    • 客户端该如何处理 csrf token
    • 针对 csrf 的一些配置项

背景

正在使用 Django 框架做项目,需要在页面上进行 POST 请求,请求由 axios 进行处理。
处理过程中总是出现 403 Forbidden,于是仔细研究了一下。

Django 的跨站请求伪造(csrf)防御

如果你啥也不想管,就想让自己的 403 消失,那么可以直接看下一节。

首先什么是 csrf,以及通用的防御措施是什么?可以参考 这个教程,这里不作赘述。
Django 提供了 csrf 防御的中间件(middleware)。做法是提供 csrf token,在收到请求时对 csrf token 进行校验。这个功能是默认打开的,在 settings.py 中的 MIDDLEWARE 里有一项 django.middleware.csrf.CsrfViewMiddleware,这个就是提供 csrf 防御能力的中间件。
需要注意的是,这个中间件需要放在任何具体页面处理的中间件前边。

取消 csrf 防御

如果你想彻底取消 csrf 防御,那么通过在 Django 项目的 settings.py 里找到 MIDDLEWARE,把 'django.middleware.csrf.CsrfViewMiddleware', 这一项注释掉,重启一下服务就好。

如果你希望对某几个特定的处理取消 csrf 防御,那么在对应的处理函数前加上修饰符即可。

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def HandlePost(request):
    ...
    # 这里的 HandlePost 就是用来处理 post 请求的
    # 增加 csrf_exempt 修饰符后,该请求关闭 csrf token 的校验

对某个特定请求开启 csrf 防御

Django 的 csrf 防御默认只校验 POST 请求,对 GET、PUT 等方法不做处理。
通过一个修饰符,可以为某个特定的页面开启 csrf 校验。

from django.views.decorators.csrf import csrf_protect

@csrf_protect
def HandleGet(request):
    ...

设置 csrf token

当我们设置了某个请求是需要 csrf 校验的,就意味着前端在进行请求时,需要加上 csrf token,那么第一步就是怎么把 csrf token 给到客户端。

其实如果开启了 csrf 中间件,那么在请求返回时,就会种下 csrftoken 这个 Cookie。

当然也可以把 csrf token 放到页面中。如果使用了 Django 提供的模板(template),那么,可以在模板中直接加入 {% csrf_token %},这个标签会被渲染成一个隐藏的 input,它的 value 就是 csrf token。

客户端该如何处理 csrf token

如果进行请求的是一个表单,直接将这个标签放入表单里即可,形如

<form method="post">
    {% csrf_token %}
    ...
form>

Django 会自动进行处理;如果觉得这样不方便,那么就需要在 header 中加入相关的信息。默认的 csrf header 名称是 X-CSRFTOKEN,我们以 axios 为例,进行说明

axios.post('/api/general/addTorrent/', {
        foo: 'bar'
    }, {
        headers: {
            'content-type': 'application/x-www-form-urlencoded'
        },
        xsrfHeaderName: 'X-CSRFTOKEN', // 设置 csrf token header 的名称
        xsrfCookieName: 'csrftoken' // 从 cookie 中获取 csrftoken
    })
    .then(response => {
            // 对返回的数据进行处理
        }
    })

针对 csrf 的一些配置项

项目的 settings.py 中可以对 csrf 策略做一些配置:

CSRF_COOKIE_NAME # 默认 csrftoken
CSRF_HEADER_NAME # 头的名字,默认 HTTP_X_CSRFTOKEN,对应 X-CSRFTOKEN,即最后用的名称前边加上 HTTP_
CSRF_TRUSTED_ORIGINS # 信任的域名,默认 []
CSRF_FAILURE_VIEW # 默认 django.views.csrf.csrf_failure

CSRF_COOKIE_HTTPONLY # 默认 false,如果有 HTTPONLY 标志,那么 JS 读不到……
CSRF_COOKIE_AGE # 默认 31449600 秒,即一年

你可能感兴趣的:(Python学习,Python,Django,csrf)