为什么对 'localhost:8000' 的 CSRF POST 请求成功,但对 '127.0.0.1:8000' 不成功?

问题描述 投票:0回答:1

我的前端(React)和后端(Django)是解耦的,分别运行在

localhost:3000
127.0.0.1:8000
上。

考虑以下前端请求:

async function test() {
    let token = await getCsrfToken() // fetched from other endpoint
    let url = 'http://localhost:8000/test'
    let response = await fetch(url, {
        method: 'POST',
        headers: {
            'X-CSRFToken': token,
        },
        credentials: 'include',
    })
    let response_text = await response.text()
    return response_text
}
test() 

到以下端点:

def test(request):
    return HttpResponse('OK')

效果很好。但如果我改变:

let url = 'http://localhost:8000/test'

至:

let url = 'http://127.0.0.1:8000/test'

它将失败:

禁止(未设置 CSRF cookie。):/test

根据我的理解,

localhost
127.0.0.1
应该是同义词。为什么在这种情况下不是这样?

更让我困惑的是,Django 的开发服务器显式运行在

127.0.0.1:8000
上。

注意:我正在使用

django-cors-headers
中间件和以下 CORS/CSRF 设置:

CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = ['http://localhost:3000']
CSRF_TRUSTED_ORIGINS = ['localhost:3000']
python django cors csrf
1个回答
0
投票

问题是 127.0.0.1 和 localhost 被认为是不同的域,至少在我的情况下是这样。因此,当CSRF token从后端发送到前端时,需要进行额外的配置。 在我的

@GetMapping("/csrf")
public CsrfToken csrfToken(CsrfToken token, HttpServletResponse response) {
    response.setHeader(HttpHeaders.SET_COOKIE, "XSRF-TOKEN=" + (token == null ? "" : token.getToken()) + "; Path=/; SameSite=Lax; Secure");
    return token;
}

添加的重要部分是

SameSite=Lax; Secure
这会起作用,但如果不行的话,请查看同一个站点的无、宽松、严格的文档,看看您真正需要什么

  • SameSite=None:在所有请求中发送 Cookie,无论是同站点还是跨站点。然而,他们要求 cookie 是安全的,这意味着它是通过 HTTPS 访问的。
  • SameSite=Lax:在某些跨站请求中发送 Cookie,但只有在满足两个条件时才会发送:请求必须是顶级导航(例如,当地址栏中的 URL 发生变化时,用户单击链接)去另一个站点)并且请求的方法必须是安全的(例如 GET 或 HEAD,但不是 POST)。
  • SameSite=Strict:Cookie 绝不会在跨站点请求中发送,即使在顶级导航中也是如此。这意味着,如果用户在 site-a.com 上并单击指向 site-b.com 的链接,则来自 site-a.com 的 SameSite=Strict cookie 将不会随请求一起发送。

我现在使用samesite=lax,只是因为127.0.0.1和localhost是http而不是https,所以我不能使用samesite=none

© www.soinside.com 2019 - 2024. All rights reserved.