【问题标题】:Django how to validate POST ParametersDjango如何验证POST参数
【发布时间】:2015-11-20 14:36:58
【问题描述】:

我通过 POST 请求将一些参数传递给 django。如何验证参数是否为整数、字符串以及内部是否存在代码注入等不安全的东西? 有我可以使用的 django 函数吗?

例如:

if request.method == 'POST':
    print request.POST.get('user_comment')

如何检查 POST 参数是否包含对我的系统来说不危险的字符串?像

request.POST.get('user_comment').is_valid()

谢谢。

【问题讨论】:

    标签: python django validation post parameters


    【解决方案1】:

    为了检查POST 数据是否安全、类型是否正确等,您可以在 django 中使用表单。例如,如果您期望 3 个必需参数,一个字符串和 2 个整数,您可以创建表单:

    from django import forms
    
    class MyValidationForm(forms.Form):
        first = forms.CharField()
        second = forms.IntegerField()
        third = forms.IntegerField()
    

    并在视图中使用它:

    if request.method == 'POST':
        form = MyValidationForm(request.POST, request.FILES)
        if not form.is_valid():
            # print some error here
        else:
            # do whatever you like
    

    如果字符串不包含危险的东西,则过滤,没有通用的解决方案。数据库、XSS 等存在不同的威胁,因此无法全部过滤。

    【讨论】:

    • is_valid() 函数是否只检查参数是否适合 CharField 或 IntegerField 等。与 xss 等无关?
    • 在 django 中有不同的方法可以防止 XSS 或 SQL 注入。 XSS 的正确方法内置于模板中。对于 SQL 注入,如果您不使用原始查询或 extra,ORM 将完成这项工作
    【解决方案2】:

    如果您使用的是 Django REST Framework,那么您可以在视图中执行以下操作。

    from rest_framework import status
    from rest_framework.views import APIView
    
    class MyView(APIView):
      def post(self , request):
        serializer = MySerializer(data = request.data)
        if serializer.is_valid():
          serializer.save()
          return Response({"status" : "Success"} , status = status.HTTP_201_CREATED)
    

    如果您不使用 DRF,请查看 serializers.py 以了解 is_valid() 是如何实现的。基本上,它调用django.db.models.fieldsrun_validators() 函数。希望这会有所帮助!

    【讨论】:

    • 此方法期望在每个 API 请求后面都有一个模型。我的意思是拥有一个序列化器意味着拥有一个模型。如果我只想在没有模型的情况下验证 API 请求怎么办?
    • 如果您知道 request.data 包含的参数/字段,完全有可能在没有 Django 模型的情况下使用 Serializer。
    • 是的,我可以在阅读文档并自己尝试后弄清楚。
    【解决方案3】:

    您可以考虑在您的字段之前使用cleaned_ 对其进行验证。 例如,如果你想检查用户名,并且你已经为它定义了一个模型,

    class MyModel(models.Model):
        username = model.CharField(max_length = 255)
    

    那么你有一个类似下面的表格

    class MyForm(forms.ModelForm):
        class Meta:
            model = MyModel
            fields = ['username']
    
        def clean_username(self):
            username = self.cleaned_data.get('username')
            """ this will give you the actual username from the field
                Now you may get that validated
            """
            if username == "blah blah":
                return forms.ValidationError("This isnt any name!")
            else:
                return username
    

    这是根据 django 文档说的:

    “Field 子类上的 clean() 方法负责以正确的顺序运行 to_python()、validate() 和 run_validators() 并传播它们的错误。如果任何时候,任何方法引发 ValidationError ,验证停止并引发错误。此方法返回干净的数据,然后将其插入到表单的cleaned_data字典中。

    clean_() 方法在表单子类上调用——其中替换为表单字段属性的名称。此方法执行特定于该特定属性的任何清理,与它的字段类型无关。该方法不传递任何参数。您需要在 self.cleaned_data 中查找该字段的值,并记住此时它将是一个 Python 对象,而不是表单中提交的原始字符串(它将在 clean_data 中,因为通用字段 clean() 方法,上面已经清理过一次数据了)。”

    【讨论】:

      【解决方案4】:

      最简单的方法是创建一个表单:

      from django import forms
      
      class SingleForm(forms.Form):
          user_comment = forms.CharField(max_length=100)
      

      然后

      comment = SingleForm(request.POST or None)
      if comment.is_valid():
          # here everything is cleaned and safe
      

      或者你想在没有表格的情况下这样做?

      【讨论】:

        【解决方案5】:

        关于代码注入,您可以使用bleach 清理用户输入:

        >>> import bleach
        >>> bleach.clean('an <script>evil()</script> example')
        u'an &lt;script&gt;evil()&lt;/script&gt; example'
        

        您可以在 Django 官方文档中找到有关安全性的更多信息:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-08-05
          • 2017-06-09
          • 2019-07-18
          • 2020-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-04
          相关资源
          最近更新 更多