2017-07-25 30 views
1

最近我一直在研究AngularJS和Django。 AngularJS承诺自动处理名为'XSRF-TOKEN'的传入cookie并添加名为'X-XSRF-TOKEN'的请求标头。所以我设置在settings.py Django的变量:【django-1.11.3/angular-1.6.4】POST AJAX CSRF验证失败

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

显然,作为隐含here它无法正常工作。 所以我不得不安装angular-cookies.js模块来检索'csrftoken'cookie,并将它的值放在请求头'X-CSRF-TOKEN'中。但是,它仍然无法正常工作。那么这次呢,它一定是在服务器端。

HTML模板:

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

显然我在我的HTML表单中有{%csrftoken%}。 当我在Firefox中检查我的数据包时,我有两个标头'Cookie'和'X-CSRF-TOKEN'。

错误页面截图: enter image description here

+0

错误是什么? –

+0

@Kashif Siddiqui我只是附加了一个截图和一个链接到我的页面。 –

回答

0

解决方案

编辑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 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) 

如图所示,我插了几行,以帮助确定发生了什么事在这个函数。

要我supprise,当我检查出/var/log/apache2/error.log检索Django的输出,我发现request_csrf_token在阶段1和阶段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在其document中。