检查Django表单的有效性和javascript

时间:2019-11-28 10:05:07

标签: javascript django forms validation

我正在使用django模型表格,我想保护我免受恶意用户输入(不仅仅是错误输入)。

据我所知,django表格足够安全:.is_valid()检查用户输入,csfr防止跨站点伪造。

但是这次,我的表单没有使用action='/path/to/my/view'来调用django视图,而是我的Submit按钮调用了javascript函数,并且此函数获取数据并使用ajax调用django视图来访问数据库,然后在屏幕上显示结果。

因此,我认为不再受保护了(不调用.is_valid(),不发送csfr)。我是对的?如果可以,我该怎么办?

我认为:

1)这不是问题,表格是合理安全的(为什么?)

2)重构代码并使用Django视图

3)django表单验证都不足够安全,因此无论如何我都应该做更多(什么?)

4)我的JavaScript函数正在使用ajax将数据发送到django视图。我应该使用该数据实例化绑定表单并在其上使用.is_valid(),但是无论如何我都没有使用csfr,对吧?

5)使用html验证器(对我来说,它们看起来不适应检查恶意输入数据)

6)其他?

一些代码是完整的,但很可能您将不需要它

我的forms.py

class NameListForm(forms.ModelForm):
    class Meta:
        model = Name
        fields = ['namelanguage', 'nametype', 'gender']
        widgets = {
            'gender': forms.CheckboxSelectMultiple(),
        }

我的models.py

class Name(models.Model):
    name = models.CharField(_('nome'), max_length=50, default='')
    namelanguage = models.ForeignKey(
        NameLanguage, related_name='%(app_label)s_%(class)s_language',
        verbose_name=_('linguaggio'), on_delete=models.PROTECT)
    nametype = models.ForeignKey(
        NameType, related_name='%(app_label)s_%(class)s_tipo',
        verbose_name=_('tipo'), on_delete=models.PROTECT)
    gender = models.ForeignKey(
        Gender, related_name='%(app_label)s_%(class)s_gender',
        verbose_name=_('sesso'), on_delete=models.PROTECT,
        blank=True, null=True)

我的template.html

<form action="" method="post">
    <div>
        <div class="col-md-auto">
          {{ name_list_form.namelanguage.label_tag }}<br />
          {{ name_list_form.namelanguage }}
          {{ name_list_form.namelanguage.errors }}
        </div>
        <div class="col-md-auto">
          {{ name_list_form.nametype.label_tag }}<br />
          {{ name_list_form.nametype }}
          {{ name_list_form.nametype.errors }}
        </div>
        <div class="col-md-auto">
          {{ name_list_form.gender.label_tag }}<br />
          {{ name_list_form.gender }}<br />
          {{ name_list_form.gender.errors }}
        </div>
    </div>
    {{ name_list_form.non_field_errors }}
    <div>
        <button class="btn btn-primary" id='list_name' type="button" onclick="FilterBy()">{% trans "List Names" %}</button>
        <button class="btn btn-primary" type="button" onclick="RandomNames()">{% trans "Random Names" %}</button>
    </div>
    {% csrf_token %}
</form>

我的javascript.js

function FilterBy() {
    var language_id = document.getElementById("id_namelanguage").value;
    var nametype_id = document.getElementById("id_nametype").value;
    ...

    $.ajax({type: 'POST',
        url: '/lists/get-list-name/',
        data: {
            language: language_id,
            nametype: nametype_id,
            ...
        },
        success: function (lista) {
            if (lista.result === 'OK') {
            //do something
            };
        }
     });
};

我的views.py

def GetListName(request):
    if request.is_ajax():
        language = request.POST.get('language')
        nametype = request.POST.get('nametype')
        # it makes sense to check validity here? and anyway I'm not using csfr, right?
        # name_list_form = NameListForm({'namelanguage': language, 'nametype': nametype, etc})
        # if name_list_form.is_valid():
        ...
        return JsonResponse({'result': 'OK', 'data': my_dict})

1 个答案:

答案 0 :(得分:1)

CSRF和数据有效性是两个不同的主题。

首先,您可以通过在请求标头check this中发送CSRF令牌来检查CSRF错误。

第二,您可以使用JS发送数据的方式与传统形式相同。

// JS, don't forget to add your CSRF headers
$.ajax({
  method: "post",
  url: "...",
  data: {
    namelanguage: "foo",
    nametype: "bar",
    gender: "baz",
  });

然后像您一样处理表单。如果您不确定自己的表单是从JS脚本提交的,则可以抛出异常,但这不能保证您确实如此。任何人都可以修改客户端标头,以使您这么认为。

# python
from django.http.response import HttpResponseBadRequest, HttpResponseNotAllowed

def GetListName(request):
    if not request.is_ajax():
        return HttpResponseNotAllowed()
    form = NameListForm(data=request.POST)
    if not form.is_valid():
        return HttpResponseBadRequest()

    # do stuff with your form
    return JsonResponse({'result': 'OK', 'data': 'some data'})