为什么在发送POST请求到Localhost:8000时,CSRF cookie设置了,而在发送POST请求127.0.0.1.1:8000时则不设置?
为什么在发送POST请求到Localhost:8000时,CSRF cookie设置了,而在发送POST请求127.0.0.1.1:8000时则不设置?然后,Django抱怨未设置CSRF Cookie。 (假设我使用localhost:3000打开前端,那么使用127.0.0.0.1:3000打开前端脚本时就会发生相同的现象,但是这个时间帖子请求仅通过127.0.0.0.1:8000)。 基本上,我对如何配置事物感兴趣,以便以后能够从两个不同的域中使用前端(在我的情况下进行反应)和后端(Django)。目前,我没有登录功能等。因此,CSRF保护没有意义。但是,我很感兴趣,为什么对于当前的配置,我无法使用CSRF令牌在标题中执行交叉原点请求(post)。
因此,这是我的代码:
前端:
export async function post_request_to_backend_with_csrf(url : string, data: {[key: string] : string}, headers: AxiosRequestHeaders | undefined = undefined) : Promise<AxiosResponse<any, any>> {
// get csrf token
var csrftoken = getCookie('csrftoken');
if (csrftoken === null) {
await getCSRFToken().then(
(response) => {
csrftoken = getCookie('csrftoken');
}
). catch((e) => console.log(e))
}
var headers_arg : AxiosRequestHeaders = {'X-Requested-With': 'XMLHttpRequest', 'X-CSRFToken': csrftoken!, 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'};
for (let key in headers) {
if (!(key in headers_arg)) {
headers_arg[key] = headers[key];
}
}
return axios.post(
url,
data,
{ //
withCredentials: true, // send cookies, authorization headers or TLS client certificates cross -origin.
headers: headers_arg // contains CSRF cookie among others.
});
}
function getCSRFToken() {
return axios.get(CSRF_URL, {withCredentials: true});
}
后端:
# settings.py
# ...
######## CORS SETUP ###########
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = [
# defaults
"accept",
"accept-encoding",
"authorization",
"content-type",
"dnt",
"origin",
"user-agent",
"x-csrftoken",
"x-requested-with",
# added
"X-CSRFTOKEN",
'access-control-allow-origin',
]
CORS_EXPOSE_HEADERS = [] + CORS_ALLOW_HEADERS
CORS_ALLOW_METHODS = [
"DELETE",
"GET",
"OPTIONS",
"PATCH",
"POST",
"PUT",
]
######## END of CORS SETUP ####
######## CSRF SETUP ###########
CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS=["http://localhost:3000", "http://127.0.0.1:3000"]
####### END CSRF SETUP ########
总结我尝试实现: https://docs.djangoproject.com/en/4.0/4.0/ref/ref/csrf/ #:〜:text =%3C/脚本%3E-,设置%20%20Token%20on%20 the%20AJAX%20request,-%c2%b6 ,但对于交叉孔的请求,最后一部分'工作。
更新:
通过仔细观察,我意识到,在通过交叉启示请求请求CSRF-Token时,将在响应中获得cookie。即响应的标题包含set-cookie:csrftoken:“ ...”,但是它没有设置(我在开发人员工具中找不到它 - &gt; storage - &gt; cookie),因此JS无法访问。我想知道问题是否是通过不安全的请求访问Localhost ...
Why is the csrf cookie set when sending POST request to localhost:8000, but not when sending POST request 127.0.0.1:8000? Django then complains that the CSRF cookie is not set. (Assuming I open the frontend using localhost:3000, then same phenomenon occurs when opening the frontend script using 127.0.0.1:3000 but this time POST requests go through only to 127.0.0.1:8000).
Basically, I'm interested on how to configure things in order to be able later on to serve the frontend (React in my case) and the backend (Django) from two different domains. For now I have no login feature etc. so CSRF protection makes no sense. However I'm interested, why with the current configuration, I'm not able to do cross origin requests (POST) with the CSRF token being in the header.
So here is my code:
Frontend:
export async function post_request_to_backend_with_csrf(url : string, data: {[key: string] : string}, headers: AxiosRequestHeaders | undefined = undefined) : Promise<AxiosResponse<any, any>> {
// get csrf token
var csrftoken = getCookie('csrftoken');
if (csrftoken === null) {
await getCSRFToken().then(
(response) => {
csrftoken = getCookie('csrftoken');
}
). catch((e) => console.log(e))
}
var headers_arg : AxiosRequestHeaders = {'X-Requested-With': 'XMLHttpRequest', 'X-CSRFToken': csrftoken!, 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'};
for (let key in headers) {
if (!(key in headers_arg)) {
headers_arg[key] = headers[key];
}
}
return axios.post(
url,
data,
{ //
withCredentials: true, // send cookies, authorization headers or TLS client certificates cross -origin.
headers: headers_arg // contains CSRF cookie among others.
});
}
function getCSRFToken() {
return axios.get(CSRF_URL, {withCredentials: true});
}
Backend:
# settings.py
# ...
######## CORS SETUP ###########
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = [
# defaults
"accept",
"accept-encoding",
"authorization",
"content-type",
"dnt",
"origin",
"user-agent",
"x-csrftoken",
"x-requested-with",
# added
"X-CSRFTOKEN",
'access-control-allow-origin',
]
CORS_EXPOSE_HEADERS = [] + CORS_ALLOW_HEADERS
CORS_ALLOW_METHODS = [
"DELETE",
"GET",
"OPTIONS",
"PATCH",
"POST",
"PUT",
]
######## END of CORS SETUP ####
######## CSRF SETUP ###########
CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS=["http://localhost:3000", "http://127.0.0.1:3000"]
####### END CSRF SETUP ########
In summary I tried to implement: https://docs.djangoproject.com/en/4.0/ref/csrf/#:~:text=%3C/script%3E-,Setting%20the%20token%20on%20the%20AJAX%20request,-%C2%B6 but for cross-origin requests, where the last part doesn't work.
Update:
By taking a closer look, I realized that basically when requesting the csrf-token via a cross-origin request, the cookie is obtained in the response. I.e. the header of the response contain Set-Cookie: csrftoken: "...", however it is not set (I cannot find it in Developer Tools --> Storage --> Cookies) and hence not accessible for the JS. I wonder if the issue is that localhost is accessed by insecure requests...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通过更准确地查看浏览器设置,我发现了以下内容。
对于交叉原始请求:localhost-&gt; 127.0.0.1,设置了cookie(可以单击URL左Chrome中的(i)来看到它),但无法访问JavaScript(不在DevTools&gt; storage&gt; cookies中)。 JavaScript永远无法读取/访问来自不同来源的cookie。
现在,CSRF代币通过保证令牌和cookie匹配来保护,并且只有有效的起源才能访问令牌。由于JavaScript无法读取不同原点的Cookie,因此必须使用Django Template {%CSRF_TOKEN%}直接从服务器获得CSRF令牌。在这里,CORS策略确保没有攻击者能够通过阻止攻击者的请求来获得CSRF令牌,即通过阻止所有不来自有效前端的请求来获得攻击者的要求。该CORS策略由浏览器执行,因此恶意应用程序仍然可以检索到CSRF令牌,但是由于CSRF攻击只能在浏览器中发生,因此这再次不是问题。
显然,应该更改
为
By looking more exactly at the browser setup, I found out the following things.
For the cross-origin request: localhost --> 127.0.0.1, the cookie (can see it by clicking on the (i) in Chrome left of the URL) was set but not accessible for JavaScript (not in DevTools > Storage > Cookies). Cookies that come from a different origin can never be read/accessed by JavaScript.
Now, the CSRF token protects by guaranteeing that the token and the cookie match and that only valid origins may access the token. Since cookies of a different origin cannot be read by JavaScript, the CSRF token must be obtained directly from the server, using the Django template {% csrf_token %} for example. Here, the CORS policy makes sure that no attacker is able to get the CSRF token, by blocking the attackers requests, i.e. by blocking all requests that don't come from the valid frontend. This CORS policy is enforced by the browser, so a malicious app could still retrieve then CSRF token, but since CSRF attacks can only happen in a browser, this again is not a problem.
Obviously, one should change
to