簡體   English   中英

使用 CSRF_COOKIE_HTTPONLY 將 Django CSRF 令牌傳遞給 Angular

[英]Pass Django CSRF token to Angular with CSRF_COOKIE_HTTPONLY

在 Django 中,當CSRF_COOKIE_HTTPONLY設置為 True 時,CSRF cookie 獲得 httponly 標志,這從安全角度來看是可取的,但打破了將此 cookie 添加到 httpProvider 的標准角度解決方案,如下所示:

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

通過 Django 1.9,有一個解決方法,您可以通過將 cookie 放入模板中直接將 cookie 傳遞給應用程序:

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

並將其放入角度應用程序中:

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

不幸的是,這不適用於 Django 1.10+ 中的單頁 Angular 應用程序,因為 CSRF cookie 在每次請求后都會更改。 CSRF_COOKIE_HTTPONLY設置開啟的情況下,如何從 Angular 向 Django 1.10+ 發出 post 請求?
注意:禁用 CSRF 保護不是一個可接受的答案。

我認為這個問題在這次討論中得到了很好的回答。

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

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

CSRF_COOKIE_HTTPONLY 不為單頁應用程序提供任何額外的安全性。 有些人推薦了這個解決方案

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

但是,或者如果您正在為您的應用程序公開 csrftoken,沒有什么可以阻止惡意用戶獲取並使用它。 如果您正在運行單頁應用程序,您不妨設置 CSRF_COOKIE_HTTPONLY=False,根據下面的評論:

加文·沃爾 5/4/15

怎么樣? 您不能只是從不同域中獲取 ajax 內容。

我說的是單個域。 在不包含 CSRF 令牌的頁面上注入 javascript 可以獲取同一域上的不同頁面以獲取它。

如果您已經將 javascript 注入到受害者頁面 (XSS) 中,則無需獲取 CSRF 令牌,您已經獲得了更大的控制權。

好吧,HttpOnly 標志旨在減少攻擊者一旦可以注入 javascript 就可以造成的損害。 但我同意——從 javascript 中隱藏 CSRF 令牌不會以任何方式增加安全性,但文檔暗示它確實如此。 我想在文檔中明確說明這個設置沒有任何意義。

如果您仍然認為那里有一個有效的攻擊向量,請將其發送到 secu...@djangoproject.com 並添加更多解釋。

沒有攻擊向量。 這只是關於誤導性的文檔。

Django 對此有一個文檔化的解決方案 即使 CSRF_COOKIE_HTTPONLY 被啟用,只要 CSRF 令牌在 DOM 中,任何 Javascript 都可以從 DOM 中獲取 CSRF 令牌。

第 1 步:我添加一個標簽讓 Django 中間件將 csrf 令牌放入 DOM

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

第 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) });
  }
}

第 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