【问题标题】:Handling CSRF tokens in Django在 Django 中处理 CSRF 令牌
【发布时间】:2013-05-05 00:32:38
【问题描述】:

我编写了一个小的独立 python 脚本,它调用了我基于 django 的后端,并且在登录和调用需要身份验证的视图等方面一切正常。

一点代码

def dostuff():
    session = login(username, password)
    license = add_license(session)

def _helper(self, url, cookie=None):
    http = httplib2.Http()
    if cookie:
        headers = { "Cookie" : cookie }
    else:
        headers = {}
    response, content = http.request(host + url, "GET", headers=headers, body="")
    return response, content

def login(self, username, password):
    url = "/license/login?username=%s&password=%s" % (username, password)
    response, content = self._helper(url)
    sessioncookie = response["set-cookie"]
    customer_id = re.search("id=(?P<id>\d+)", content)
    if response["status"] == "200":
        return sessioncookie, customer_id.group("id")

def add_license(self, session):
    cookie = session[0]
    customer_id = int(session[1])-1
    url = "/license/add_license?customer_id=%s" % customer_id
    response, content = self._helper(url, cookie)
    content = content[1:-1]
    if response["status"] == "200": #ok
        data = json.loads(content)
        return data["fields"]

如果我将“GET”更改为“POST”,我会遇到 Django CSRF 错误页面(CSRF 验证失败)作为回报。如何向 Django 发送 POST 数据?

我在 Django 中的登录视图,我需要做一些特别的事情来添加 csrf 令牌吗?我的计划是在一切正常后重写它以发送 json。

 def my_login(request):
    done, username = get_input(request, "username")
    if not done:
        return username
    done, password = get_input(request, "password")
    if not done:
        return password
    user = authenticate(username=username, password=password)
    if user is not None:
       if user.is_active:
            login(request, user)
            return HttpResponse("Done, id=%s" % user.pk)
        else:
            return HttpResponse("User disabled")
    else:
        return HttpResponse("Invalid login")

【问题讨论】:

    标签: django python-2.7


    【解决方案1】:

    当您向 Django 发出请求时,您必须添加 csrftoken cookie 值。或者,您可以将 @csrf_exempt 添加到您的 Django 后端以接受这些请求。

    【讨论】:

    • cookie = { "csrftoken" : ...somthing...? } 在我的 _helper 函数中?由于我在调用登录时收到此错误,因此我还没有收到任何 cookie。
    • 检查您的 csrftoken 是否安全,以及您的请求是否与该协议相同。 https 如果它是安全的,http 是不是。
    • 添加了我的登录视图,我不确定如何检查令牌是否安全。
    • @dutt:cookie 不依赖于是否被记录。任何 http 请求都足以在浏览器中接收 cookie。不要使用@csfr_exempt,除非你确定你不需要它。阅读here 了解CSFR 和Django。
    • 在这一点上让我感到困惑的是,我在登录尝试时被 csrf 拒绝。那时我还没有与服务器有任何联系,也不知道要发送什么作为 csrftoken cookie。
    【解决方案2】:

    开始阅读CSFR and ajax。我通常使用提供的代码执行以下操作:

    1. 创建一个 csfr.js 文件
    2. 在 csfr.js 文件中粘贴 the code
    3. 引用模板中需要的代码|

    如果您使用模板并且有类似 base.html 之类的东西,您可以从那里进行扩展,那么您可以从那里引用脚本,而您不必再担心其他的编程。据我所知,这不应该代表任何安全问题。

    【讨论】:

    • 我没有使用模板,我以前使用过它们并让 csrf 工作,但现在我很好奇是否可以不使用模板。我见过的所有解决方案都依赖于模板,我只是将 HttpResponse 与原始文本一起使用。但到目前为止,似乎最简单的解决方案毕竟是使用模板。
    • 我明白了,但在这种情况下,只需确保执行提供的代码即可。最后 3 行代码调用方法 xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));。如果您将代码粘贴到当前 javascript 文件的开头,那么它应该可以工作。
    【解决方案3】:

    我让它工作了,我就是这样做的。就像 toto_tico 建议的那样,我写了一个虚拟视图,我检索了 GET 来获取 CSRF 令牌。起初它没有通过 GET 发送 csrf 令牌,所以我不得不添加装饰器 ensure_csrf_cookie。

    @ensure_csrf_cookie
    def dummy(request):
        return HttpResponse("done")
    

    然后我正常处理登录请求。

    def my_login(request):
        ...handle login...
    

    事实证明,仅将 cookie 添加到 POST 是不够的,我还必须将令牌写入 POST 数据。

    def _helper(self, url, method="POST"):
        req = urllib2.Request(host + url)
        self.cookieMgr.add_cookie_header(req)
        try:
            if method == "GET":
                response = self.opener.open(req)
            else:
                for cookie in self.cookieMgr:
                    if cookie.name == "csrftoken":
                        csrf = cookie.value
                values = { "csrfmiddlewaretoken" : csrf}
                params = urllib.urlencode(values)
                response = self.opener.open(req, params)
                code = response.getcode()
                info = response.info()
                content = response.read()
                return code, info, content
        except urllib2.HTTPError as ex:
            print str(ex)
            sys.exit(1)
    
    def get_csrf(self):
        url = "/license/dummy"
        self._helper(url, method="GET")
    
    def login(self, username, password):
        self.get_csrf()
        url = "/license/login?username=%s&password=%s" % (username, password)
        code, info, content = self._helper(url)
        if code == 200:
            #done!
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-19
      • 2019-02-26
      • 1970-01-01
      • 2013-08-11
      • 2016-08-03
      • 1970-01-01
      • 2021-07-14
      • 1970-01-01
      相关资源
      最近更新 更多