【问题标题】:Add CSRF token to hard coded Django form将 CSRF 令牌添加到硬编码的 Django 表单
【发布时间】:2018-07-28 12:18:13
【问题描述】:

我正在使用 Jekyll 构建一个具有硬编码表单的 静态页面,我正在将表单数据发送到 Django 服务器,但无法生成 CSRF token。我可以将数据保存到数据库的唯一方法是使用静态 csrf 令牌,该令牌既笨拙又毫无意义。

有没有更好的方法可以做到这一点?

这就是我想要的:

<form method="POST" action="http://djangoserver" >
    {% csrf_token %} <!-- Doesn't work in Jekyll -->
    <input type="text" name="name" required id="id_name" maxlength="100>
 </form>

但显然 Jekyll 不知道该令牌是什么,并且 POST 也不会将其发送到 Django 服务器。


这可行,但它很容易受到攻击和hacky,我需要每次实际生成唯一令牌的相同效果。

<form method="POST" action="http://djangoserver" >
    <input type="hidden" name="csrfmiddlewaretoken" value=" some long stuff" >
    <input type="text" name="name" required id="id_name" maxlength="100>
 </form>

【问题讨论】:

    标签: python django jekyll csrf


    【解决方案1】:

    {% csrf_token %} 不起作用,因为它是 Django 模板标签。硬编码 csrfmiddlewaretoken 也不起作用,因为此值会更改以提供安全性。

    我在 Jekyll 的博客上也遇到了类似的问题。在联系页面上,我添加了普通的 HTML 表单,其中 action 指向我的 Django 后端。对于这个视图,我使用 @csrf_exempt 装饰器移除了 CSRF 令牌验证。

    为避免滥用,我添加了 Google Recaptcha 验证。

    看下面的例子:

    from django.conf import settings
    from django.views.decorators.csrf import csrf_exempt
    from django.views.decorators.http import require_POST
    import requests  # http://docs.python-requests.org
    
    @require_POST
    @csrf_exempt
    def ask(request):
        recaptcha_response = request.POST.get('g-recaptcha-response')
        data = {
            'secret': settings.GOOGLE_INVISIBLE_RECAPTCHA_SECRET_KEY,
            'response': recaptcha_response
        }
        r = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data)
        result = r.json()
    
        if result['success']:
            # process form...
        else:
            # invalid recaptcha
    

    【讨论】:

    • 聪明,没想到
    【解决方案2】:

    如果这不在同一域中,我建议设置Django REST Framework

    如果在同一个域,那么按照Django Docs上的建议做:你可以用JavaScript获取CSRF令牌(注意我已经改了函数不用jQuery):

    // WITHOUT jQuery
    function getCookie (name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = cookies[i].trim();
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    

    更新表单(注意id):

    <form id="name-form" method="POST" action="http://djangoserver" >
        <input type="text" name="name" required id="id_name" maxlength="100>
    </form>
    

    添加 csrftoken 输入:

    var form = document.getElementById('name-form'),
        input = document.createElement('input');
    
    input.name = "csrfmiddlewaretoken";
    input.type = "hidden";
    input.value = getCookie('csrftoken');
    // ^ could be a different string depending on your settings.py file
    
    form.appendChild(input);
    

    希望对您有所帮助。

    【讨论】:

    • 因此表单位于一个域(GitHub 页面)上,而 Django 将托管在一个单独的主机上。我觉得 js 方法是最简单的,我是否可以在一台服务器上生成该令牌并将其发送到 Django,或者我是否必须为此制作 api?
    • 我认为这不可能。如果可能的话,这不是一个好主意。在这种情况下你应该做的是阅读 Django REST Framework,并使用它为你的 django 服务器创建一个 API。然后就可以接受其他域名的请求了。
    【解决方案3】:

    你正在尝试的事情是不可能的,让 Jekyll 静态页面有点动态的唯一方法是使用 JavaScript。

    您可以通过在 Django 中创建 API 来实现您想要的功能,该 API 将创建 CSRF 令牌并返回它,然后您可以将其附加到您的表单中。这样您将始终拥有动态 CSRF,但我不建议通过网络发送 CSRF 令牌,因为它不安全。

    【讨论】:

      猜你喜欢
      • 2018-10-08
      • 2012-11-19
      • 2021-12-01
      • 2019-12-22
      • 2011-12-11
      • 2017-04-13
      • 2021-10-29
      • 2018-08-09
      • 2016-09-19
      相关资源
      最近更新 更多