简体   繁体   English

使用 CSRF_COOKIE_HTTPONLY 将 Django CSRF 令牌传递给 Angular

[英]Pass Django CSRF token to Angular with CSRF_COOKIE_HTTPONLY

In Django, when the CSRF_COOKIE_HTTPONLY setting is set to True, the CSRF cookie gains the httponly flag, which is desirable from a security perspective, but breaks the standard angular solution of adding this cookie to the httpProvider like so:在 Django 中,当CSRF_COOKIE_HTTPONLY设置为 True 时,CSRF cookie 获得 httponly 标志,这从安全角度来看是可取的,但打破了将此 cookie 添加到 httpProvider 的标准角度解决方案,如下所示:

$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';

Through Django 1.9, there was a workaround where you could just pass the cookie directly to the app by putting this in the template:通过 Django 1.9,有一个解决方法,您可以通过将 cookie 放入模板中直接将 cookie 传递给应用程序:

<script>
    window.csrf_token = "{{ csrf_token }}";
</script>

And putting this in the angular app:并将其放入角度应用程序中:

angularApp.config(["$httpProvider", function($httpProvider) {
    $httpProvider.defaults.headers.common["X-CSRFToken"] = window.csrf_token;
}]

Unfortunately, this doesn't work for single page angular apps in Django 1.10+ since the CSRF cookie changes after every request.不幸的是,这不适用于 Django 1.10+ 中的单页 Angular 应用程序,因为 CSRF cookie 在每次请求后都会更改。 How do you make post requests from Angular to Django 1.10+ with the CSRF_COOKIE_HTTPONLY setting on?CSRF_COOKIE_HTTPONLY设置开启的情况下,如何从 Angular 向 Django 1.10+ 发出 post 请求?
NB: Disabling CSRF protection is not an acceptable answer.注意:禁用 CSRF 保护不是一个可接受的答案。

I think this question was answered well in this discussion.我认为这个问题在这次讨论中得到了很好的回答。

https://groups.google.com/forum/#!topic/django-developers/nXjfLd8ba5k https://groups.google.com/forum/#!topic/django-developers/nXjfLd8ba5k

https://code.djangoproject.com/ticket/27534 https://code.djangoproject.com/ticket/27534

CSRF_COOKIE_HTTPONLY does not provide any additional security for single page apps. CSRF_COOKIE_HTTPONLY 不为单页应用程序提供任何额外的安全性。 Some people reccomended this solution有些人推荐了这个解决方案

var csrftoken = getCookie('csrftoken');
if (csrftoken === null) {
    csrftoken = $('input[name="csrfmiddlewaretoken"]').val();
    if (csrftoken === null) {
        console.log('No csrf token');
    }
}

however either or if you are exposing csrftoken for your app restfully nothing stops the malcious user from taking it and using it as well.但是,或者如果您正在为您的应用程序公开 csrftoken,没有什么可以阻止恶意用户获取并使用它。 If you are running a single page app you might as well set CSRF_COOKIE_HTTPONLY=False, As per comment bellow:如果您正在运行单页应用程序,您不妨设置 CSRF_COOKIE_HTTPONLY=False,根据下面的评论:

Gavin Wahl 5/4/15加文·沃尔 5/4/15

How so?怎么样? You cannot just ajax-fetch stuff from different domains.您不能只是从不同域中获取 ajax 内容。

I'm talking about a single domain.我说的是单个域。 Injected javascript on a page that doesn't contain the CSRF token can fetch a different page on the same domain to get it.在不包含 CSRF 令牌的页面上注入 javascript 可以获取同一域上的不同页面以获取它。

If you already injected javascript onto the victims page (XSS) there is no need to fetch the CSRF token, you already got greater control.如果您已经将 javascript 注入到受害者页面 (XSS) 中,则无需获取 CSRF 令牌,您已经获得了更大的控制权。

Well, the HttpOnly flag is intended to reduce the damage an attacker can do once the already can inject javascript.好吧,HttpOnly 标志旨在减少攻击者一旦可以注入 javascript 就可以造成的损害。 But I agree -- hiding the CSRF token from javascript doesn't increase security in any way, but the documentation implies it does.但我同意——从 javascript 中隐藏 CSRF 令牌不会以任何方式增加安全性,但文档暗示它确实如此。 I want to make it clear in the documentation that this setting has no meaningful effect.我想在文档中明确说明这个设置没有任何意义。

If you still think you have a valid attack vector there, please send it to secu...@djangoproject.com and add a bit more explanation.如果您仍然认为那里有一个有效的攻击向量,请将其发送到 secu...@djangoproject.com 并添加更多解释。

There is no attack vector.没有攻击向量。 This is just about misleading documentation.这只是关于误导性的文档。

Django has a documented solution for this . Django 对此有一个文档化的解决方案 Any Javascript can get the CSRF token from the DOM even if CSRF_COOKIE_HTTPONLY is enabled as long as the CSRF token is in the DOM.即使 CSRF_COOKIE_HTTPONLY 被启用,只要 CSRF 令牌在 DOM 中,任何 Javascript 都可以从 DOM 中获取 CSRF 令牌。

Step 1 : I add a tag to let Django middleware put csrf token to the DOM第 1 步:我添加一个标签让 Django 中间件将 csrf 令牌放入 DOM

 # Django put CSRF token to DOM {% csrf_token %}

Step 2 : Implement an HttpInterceptor to get csrf from DOM第 2 步:实现一个 HttpInterceptor 从 DOM 获取 csrf

import { Injectable } from '@angular/core';
import { HttpEvent, HttpRequest, HttpHandler, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class DjangoCSRFInterceptor implements HttpInterceptor {
  intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = (
      document.querySelector('[name=csrfmiddlewaretoken]') as HTMLInputElement
    ).value;
    return httpRequest.clone({ headers: httpRequest.headers.set('X-CSRFToken, token) });
  }
}

Step 3 : Put HttpInterceptor to your Angular module providers第 3 步:将 HttpInterceptor 放入 Angular 模块提供程序

 providers: [ { provide: HTTP_INTERCEPTORS, useClass: DjangoCSRFInterceptor, multi: true } ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM