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

How to use Django's CSRF protection in axios for different host?

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

我正在使用 Django CORS headers,并且我已正确完成所有设置。只要我有本地主机来访问前端和后端,它就可以工作。我的前端 运行 在 localhost:3006 上,后端我们 运行 在 localhost:8899 端口上。所以前端正在设置 csrftoken cookie 并使用 post 请求发送它。

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

我的 cors header 在 django 中的设置,

# 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 和端口从我的机器连接到我的机器,它可以工作,但是当我的 co-worker 试图从他的 localhost/IP 连接时我的 ip-backend 前端不允许他在没有 CSRF cookie 的情况下发出 POST 请求!我不想用装饰器绕过 CSRF 的 Django 安全性。那么谁能告诉我我做错了什么?

CSRF 通过将 cookie 中的令牌与 X-CSRFToken header(或表单数据)中的令牌进行匹配来工作。您的 axios 请求必须发送 both.

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

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

现在在您的测试场景中,这不起作用,因为您同事的前端设置的 cookie 是针对本地主机的,而 axios 请求是针对您的 ip。除了让您的 co-worker 也从您的 ip 获取前端外,没有其他解决方案。