如何在不同主机的 axios 中使用 Django 的 CSRF 保护?

IT技术 django reactjs axios csrf
2021-05-12 09:28:43

我正在将 ReactJS 项目作为前端,将 Django 作为后端,并且在 CSRF 保护方面遇到问题!

我正在使用 Django CORS 标头,并且已正确完成所有设置。只要我有 localhost 可以访问前端和后端,它就可以工作。我的前端在 localhost:3006 上运行,后端我们在 localhost:8899 端口上运行。所以前端正在设置csrftokencookie 并通过 post 请求发送它。

我正在使用axios.create()withCredentials = true它工作正常。现在,当我的同事从他的系统运行相同的前端代码,尝试连接到我机器上运行的后端时,他得到 403 csrf cookie not found!此时,他正在运行他的前端localhost:3006,他自己的本地主机并连接到 的后端my-ip:8899所以我相信当我们将有www.example.com服务前端和api.example.com服务后端时,我们也会在生产中遇到这个问题,因为前端主机的 cookie 不会被发送到 api 主机!

我在 Django 中的 cors 标题设置,

# Origin white list
CORS_ORIGIN_WHITELIST = [
    'http://localhost',
    'http://127.0.0.1',
    'http://192.168.1.165',
    'http://192.168.1.165:3006',
]

CORS_EXPOSE_HEADERS = (
    'Access-Control-Allow-Origin: *',
)

# Allowed methods
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
)

# Allowed headers
CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'X-tz',
    'x-tz',
    'x-requested-with',
)

# # CSRF COOKIE NAME
CSRF_COOKIE_NAME = "csrftoken"

# To allow default credentials
CORS_ALLOW_CREDENTIALS = True

CORS_ORIGIN_ALLOW_ALL = True

我的 Axios 创建代码是,

let tz = "UTC";

try {
    tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
} catch (e) {
    consoleError(e);
}

const API = axios.create({
    baseURL: process.env.REACT_APP_API_HOST,
    timeout: 30000,
    withCredentials: true,
    xsrfCookieName: CSRF_COOKIE_NAME,
    xsrfHeaderName: "X-CSRFToken",
    headers: {'X-tz': tz}
});

正如我所说,如果我使用 localhost/IP 和端口从我的机器连接到我的机器,它可以工作,但是当我的同事试图从他的 localhost/IP 前端连接到我的 ip-backend 时,它不允许他在没有 CSRF cookie 的情况下发出 POST 请求!我不想用装饰器绕过 CSRF 的 Django 安全性。那么谁能告诉我我在这里做错了什么?

1个回答

CSRF 的工作原理是将 cookie 中的令牌与 X-CSRFToken 标头(或表单数据)中的令牌进行匹配。你爱可信请求必须发送两个

它在 X-CSRFToken 中发送令牌。但它不会将 cookie 发送到 api.yourhost.com,因为 cookie 是为域 www.yourhost.com 设置的。这是 Django 中的默认设置。

更改CSRF_COOKIE_DOMAIN为以 开头的 eTLD+1 域.,即 .yourhost.com,以便将其发送到您的每个子域,包括 api.yourhost.com。

现在在您的测试场景中,这行不通,因为您同事的前端设置的 cookie 是针对 localhost 的,而 axios 请求是针对您的 ip 的。除了让您的同事也从您的 ip 获取前端之外,没有解决方案。