IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Django 之前端获取 csrftoken 的几种方式以及源码解释(超详细) -> 正文阅读

[Python知识库]Django 之前端获取 csrftoken 的几种方式以及源码解释(超详细)

表单提交时

<form action="", method="post">
    {% csrf_token %}
</form>

如果是前后端不分离的项目,django 为了防止 XSS 攻击,要求所有 form 表单提交时加上 {% csrf_token %} 标签,前端会再 html 中加入一个 input 标签<input type=“hidden”, name=‘csrfmiddlewaretoken’ value=服务器随机生成的token> django.middleware.csrf.CsrfViewMiddleware 这个中间件就是来验证 csrf_token 如果没有加,就会出错,这个 token 每次刷新页面时都会刷新,客户在请求时。会再服务器端生成一个 token,然后放在 cookie里面,每次 post 请求都会带上这个 token,去和表单里面的去对比。

  1. 官??档中说到,检验token时,只?较secret是否和cookie中的secret值?样,?不是?较整个token。

  2. token字符串的前32位是salt,后?是加密后的token,通过salt能解密出唯?的secret。

AJAX 提交时

使用表单时,必须在每个 post 上添加 csrf_token 标签,不够方便,处于这个原因,有一种替代方案,设置一个自定义的 X-CSRFToken 头(由 CSRF_HEADER_NAME 设置指定)为 CSRF 标记的值。这通常比较容易,因为许多 JavaScript 框架提供了钩子,允许在每个请求中设置头。
CSRF 令牌 cookie 默认命名为 csrftoken,但你可以通过 CSRF_COOKIE_NAME 配置来控制 cookie 的名称。
可以通过这样的方式获得 csrftoken:

function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
const csrftoken = getCookie('csrftoken');

后续可以使用这个函数来获取 csrftoken:

const csrftoken = Cookies.get('csrftoken');

在请求头中设置令牌:

const request = new Request(
    /* URL */,
    {
        method: 'POST',
        headers: {'X-CSRFToken': csrftoken},
        mode: 'same-origin' // Do not send CSRF token to another domain.
    }
);
fetch(request).then(function(response) {
    // ...
});

后续再请求时需要带上 X-CSRFToken 这个头,以postman 为例:
在这里插入图片描述

CsrfViewMiddleware 源码

想必都看到过这个报错:
在这里插入图片描述
这就是没有加 csrf_token ,要么是表单中没加,要么是没获取到 token
重点都在 django.middleware.csrf.CsrfViewMiddleware 这个中间件里面,导入之后点进去看。

# 从请求的cookie中获取csrftoken的值 
# 一般是一个键值对,key是 csrftoken  vlaue 是一串随机字符串
csrf_token = request.META.get('CSRF_COOKIE')
if csrf_token is None:
    # No CSRF cookie. For POST requests, we insist on a CSRF cookie,
    # and in this way we can avoid all CSRF attacks, including login
    # CSRF.
    # 如果获取不到,返回:CSRF cookie not set. 就是没有设置 cookie 的意思
    return self._reject(request, REASON_NO_CSRF_COOKIE)

# Check non-cookie token for match.
request_csrf_token = ""
if request.method == "POST":
    try:
    	# 从 post 里面获取 token 
        request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
    except IOError:
        # Handle a broken connection before we've completed reading
        # the POST data. process_view shouldn't raise any
        # exceptions, so we'll ignore and serve the user a 403
        # (assuming they're still listening, which they probably
        # aren't because of the error).
        pass

# 这里比较重要了
if request_csrf_token == "":
    # Fall back to X-CSRFToken, to make things easier for AJAX,
    # and possible for PUT/DELETE.
    # 如果 request_csrf_token 里面没有,就去请求头中去拿 CSRF_HEADER_NAME 
    # 默认是 X_CSRFTOKEN, 名字也可以在 setting 中自己设置
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

request_csrf_token = _sanitize_token(request_csrf_token)
# 校验表单中的 token 和 cookie 中的token是不是一致
# 检验token时,只?较secret是否和cookie中的secret值?样
# 这个 secret 应该是配置文件中的 SECRET_KEY
if not _compare_salted_tokens(request_csrf_token, csrf_token):
	# 比较失败,返回一个页面,内容就是我们熟悉的:CSRF token missing or incorrect.
    return self._reject(request, REASON_BAD_TOKEN)

装饰器方法

csrf_protect : 强制执行 csrf 验证

from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect

@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

csrf_exempt:免除 csrf 的保护

from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')

对于 CSRF cookie 常用的一些全局变量

CSRF_COOKIE_NAME = 'csrftoken'  # 默认的 key 名称
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52  # 存活时间
CSRF_COOKIE_DOMAIN = None  # 在那个域名下生效
CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'  # 请求头的名称

CSRFTOKEN 比较方式源码

每个 django 版本可能稍有不同

def _compare_salted_tokens(request_csrf_token, csrf_token):
    # Assume both arguments are sanitized -- that is, strings of
    # length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
    return constant_time_compare(
        _unsalt_cipher_token(request_csrf_token),
        _unsalt_cipher_token(csrf_token),
    )

def _unsalt_cipher_token(token):
    """
    Given a token (assumed to be a string of CSRF_ALLOWED_CHARS, of length
    CSRF_TOKEN_LENGTH, and that its first half is a salt), use it to decrypt
    the second half to produce the original secret.
    """
    salt = token[:CSRF_SECRET_LENGTH]
    token = token[CSRF_SECRET_LENGTH:]
    chars = CSRF_ALLOWED_CHARS
    pairs = zip((chars.index(x) for x in token), (chars.index(x) for x in salt))
    secret = ''.join(chars[x - y] for x, y in pairs)  # Note negative values are ok
    return secret

参考文献

django 官网:https://docs.djangoproject.com/zh-hans/4.0/ref/csrf/
Django之同源和跨域、CSRF详解:https://blog.csdn.net/qq_39253370/article/details/105684890?spm=1001.2014.3001.5501

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-06-18 23:23:49  更:2022-06-18 23:24:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 12:51:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码