django-1.11.3/angular-1.6.4:POST AJAX CSRF验证失败 [英] django-1.11.3/angular-1.6.4: POST AJAX CSRF verification failed

查看:49
本文介绍了django-1.11.3/angular-1.6.4:POST AJAX CSRF验证失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近一直在研究AngularJS和Django.AngularJS承诺处理名为"XSRF-TOKEN"的传入cookie,并自动添加名为"X-XSRF-TOKEN"的请求标头.所以我在settings.py中设置了django变量:

  CSRF_COOKIE_NAME ='XSRF-TOKEN'CSRF_HEADER_NAME ='X-CSRF-TOKEN' 

很明显,它不能按

解决方案

解决方案:

编辑 settings.py ,设置 CSRF_HEADER_NAME ='HTTP_X_CSRF_TOKEN'

我如何找到解决方案:

django CSRF保护在/usr/local/lib/python2.7/dist-packages/django/middleware/csrf.py 中实现我在其中找到函数 process_view 的位置抛出了 CSRF令牌丢失或不正确的异常:

  request_csrf_token ="如果request.method =="POST":尝试:request_csrf_token = request.POST.get('csrfmiddlewaretoken','')除了IOError:经过#< TEST>打印('[STAGE-1] request_csrf_token =',request_csrf_token,_unsalt_cipher_token(request_csrf_token)))#</TEST>如果request_csrf_token ==":request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME,'')#< TEST>打印('[STAGE-2] request_csrf_token =',request_csrf_token,_unsalt_cipher_token(request_csrf_token)))打印('request.META:')对于k,v在request.META.items()中:print('',k,v)#</TEST>request_csrf_token = _sanitize_token(request_csrf_token)#< TEST>打印('[STAGE-3] request_csrf_token =',request_csrf_token,_unsalt_cipher_token(request_csrf_token)))打印('csrf_token =',csrf_token,_unsalt_cipher_token(csrf_token))#</TEST>如果不是_compare_salted_tokens(request_csrf_token,csrf_token):返回self._reject(请求,REASON_BAD_TOKEN) 

如图所示,我插入了几行内容来帮助确定此函数中发生的事情.

令我惊讶的是,当我签出/var/log/apache2/error.log 来检索Django输出时,我发现 request_csrf_token 在两个STAGE-中都是空字符串1和STAGE-2,也就是 request.POST.get('csrfmiddlewaretoken','') request.META.get(settings.CSRF_HEADER_NAME,'') request_csrf_token 没有值.

因此,我签出了 request.META 词典BOOM,这是一个名为 HTTP_X_CSRF_TOKEN 的条目,它具有我想要的有效CSRF令牌.

显然django有这个BUG,您无法按照承诺自定义CSRF令牌HTTP请求标头名称( CSRF_HEADER_NAME )的名称.django也未能保持其文档与代码的一致性,因为 CSRF_HEADER_NAME 的默认值在HTTP_X_CSRFTOKEN .djangoproject.com/zh-CN/1.11/ref/csrf/#ajax"rel =" nofollow noreferrer>文档.

I've been studying about both AngularJS and Django recently. AngularJS promises to handle incoming cookie named 'XSRF-TOKEN' and to add a request header named 'X-XSRF-TOKEN' automatically. So I set django variables in settings.py:

CSRF_COOKIE_NAME = 'XSRF-TOKEN'
CSRF_HEADER_NAME = 'X-CSRF-TOKEN'

Obviously, it is not working as is implied here. So I had to install angular-cookies.js module to retrieve 'csrftoken' cookie and put its value in request header 'X-CSRF-TOKEN'. However, it's still not working. So what ever it is this time, it must be on server side.

HTML template:

<!DOCTYPE html>
<html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
        <title>youtube-dl</title>
        <link href="/video/css/video.css" rel="stylesheet" type="text/css">
        <script src="/js/angular-1.6.4.min.js" type="text/javascript"></script>
        <script src="/js/angular-cookies.js" type="text/javascript"></script>
    </head>
    <body>
        <div id="container" class="center" ng-app="vc" ng-controller="vc-ctl">
            <img id="dl-icon" src="/video/logo.png"></img>
            <form name="form">
                {% csrftoken %}
                <input class="url {{urlState}}" type="url" name="url" placeholder="https://" required autofocus ng-model="url">
                <button class="btn btn1" ng-if="!form.url.$valid">
                    {{ buttonText }}
                </button>
                <button class="btn btn2 {{btn2State}}" ng-if="form.url.$valid" ng-click="click();">
                    {{ buttonText }}
                </button>
            </form>
        </div>

        <script src="/video/js/app.js" type="text/javascript"></script>
    </body>
</html>

views.py:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import json

from django.shortcuts import render
from django.http import HttpResponse

from .models import VideoTask

# Create your views here.
def index(request):
    if request.method == 'GET':
        return render(request, 'video/index.html')

    stat = {
        "full_path: ", request.get_full_path(),
        "host: ", request.get_host(),
        "port: ", request.get_port(),
        "is_ajax: ", request.is_ajax(),
        "is_secure: ", request.is_secure(),
        "data: ", request.read(),
    }
    return HttpResponse(json.dumps(stat))

settings.py:

CSRF_COOKIE_NAME = 'csrftoken'
CSRF_HEADER_NAME = 'X-CSRF-TOKEN'

app.js:

var app = angular.module("vc", [
    'ngCookies'
]);
app.run(function($rootScope, $http, $cookies) {
    $rootScope.buttonText = "Submit URL";
    $http.defaults.headers.post['X-CSRF-TOKEN'] = $cookies.csrftoken;
});
app.controller("vc-ctl", function($scope, $http, $cookies) {
    $scope.cb_success = function(res) {
        $scope.progList = res.data.progList;
    };
    $scope.cb_failure = function(res) {
        console.log(res.status);
    };
    $scope.postUrl = "/wsgi/video/";
    $scope.click = function() {
        //$scope.btn2State = "hidden";
        var data = encodeURIComponent($scope.url);
        var cookie_csrf = $cookies.get('csrftoken');
        console.log("Cookie: \"" + cookie_csrf + "\"");
        console.log("POST {data: \"" + data + "\"}");
        var req = {
            method: 'POST',
            url: $scope.postUrl,
            headers: {
                'X-CSRF-TOKEN': cookie_csrf,
            },
            data: {
                url: data
            }
        };
        $http(req).then($scope.cb_success, $scope.cb_failure);
    };
    $scope.update = function() {
        $http.post($scope.postUrl, {"action": "echo"}).then($scope.cb_success, $scope.cb_failure);
    };
});

Obviously I have {% csrftoken %} in my HTML form. When I check my data parcels in Firefox, I have both headers, 'Cookie' and 'X-CSRF-TOKEN'.

Error page screenshot:

解决方案

Solution:

Edit settings.py, set CSRF_HEADER_NAME = 'HTTP_X_CSRF_TOKEN'

How I find the solution:

django CSRF protection is implemented in /usr/local/lib/python2.7/dist-packages/django/middleware/csrf.py where I located the function process_view throwed the exception CSRF token missing or incorrect:

request_csrf_token = ""
if request.method == "POST":
    try:
        request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
    except IOError:
        pass
# <TEST>
print( '[STAGE - 1] request_csrf_token=', request_csrf_token, _unsalt_cipher_token(request_csrf_token) )
# </TEST>
if request_csrf_token == "":
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
    # <TEST>
    print( '[STAGE - 2] request_csrf_token=', request_csrf_token, _unsalt_cipher_token(request_csrf_token) )
    print('request.META:')
    for k, v in request.META.items():
       print('', k, v)
    # </TEST>
    request_csrf_token = _sanitize_token(request_csrf_token)
    # <TEST>
    print( '[STAGE - 3] request_csrf_token=', request_csrf_token, _unsalt_cipher_token(request_csrf_token) )
    print( 'csrf_token=', csrf_token, _unsalt_cipher_token(csrf_token) )
    # </TEST>
    if not _compare_salted_tokens(request_csrf_token, csrf_token):
        return self._reject(request, REASON_BAD_TOKEN)

As is shown, I inserted a few lines to help determine what's going on in this function.

To my supprise, when I check out /var/log/apache2/error.log to retrieve django output, I found request_csrf_token is empty string in both STAGE-1 and STAGE-2, aka, request.POST.get('csrfmiddlewaretoken', '') and request.META.get(settings.CSRF_HEADER_NAME, '') had no value for request_csrf_token.

So I checked out request.META dictionary, BOOM, an entry named HTTP_X_CSRF_TOKEN has exactly what I want, a valid CSRF token.

Obviously django has this BUG that you can't customize the name of CSRF token HTTP request header name (CSRF_HEADER_NAME) as is promised. django also failed to keep its document compliance with its code, because the so-called default value of CSRF_HEADER_NAME is HTTP_X_CSRFTOKEN in its document.

这篇关于django-1.11.3/angular-1.6.4:POST AJAX CSRF验证失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆