Fixed #28201 -- Added ProhibitNullCharactersValidator and used it on CharField form field.

This commit is contained in:
Alejandro Zamora 2017-06-23 12:06:08 -03:00 committed by Tim Graham
parent b78d100fa6
commit 90d7b912b9
6 changed files with 88 additions and 6 deletions

View File

@ -503,3 +503,27 @@ def get_available_image_extensions():
validate_image_file_extension = FileExtensionValidator(
allowed_extensions=get_available_image_extensions(),
)
@deconstructible
class ProhibitNullCharactersValidator:
"""Validate that the string doesn't contain the null character."""
message = _('Null characters are not allowed.')
code = 'null_characters_not_allowed'
def __init__(self, message=None, code=None):
if message is not None:
self.message = message
if code is not None:
self.code = code
def __call__(self, value):
if '\x00' in str(value):
raise ValidationError(self.message, code=self.code)
def __eq__(self, other):
return (
isinstance(other, self.__class__) and
self.message == other.message and
self.code == other.code
)

View File

@ -217,6 +217,7 @@ class CharField(Field):
self.validators.append(validators.MinLengthValidator(int(min_length)))
if max_length is not None:
self.validators.append(validators.MaxLengthValidator(int(max_length)))
self.validators.append(validators.ProhibitNullCharactersValidator())
def to_python(self, value):
"""Return a string."""

View File

@ -304,3 +304,27 @@ to, or in lieu of custom ``field.clean()`` methods.
Uses Pillow to ensure that ``value.name`` (``value`` is a
:class:`~django.core.files.File`) has `a valid image extension
<https://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html>`_.
``ProhibitNullCharactersValidator``
-----------------------------------
.. class:: ProhibitNullCharactersValidator(message=None, code=None)
.. versionadded:: 2.0
Raises a :exc:`~django.core.exceptions.ValidationError` if ``str(value)``
contains one or more nulls characters (``'\x00'``).
:param message: If not ``None``, overrides :attr:`.message`.
:param code: If not ``None``, overrides :attr:`code`.
.. attribute:: message
The error message used by
:exc:`~django.core.exceptions.ValidationError` if validation fails.
Defaults to ``"Null characters are not allowed."``.
.. attribute:: code
The error code used by :exc:`~django.core.exceptions.ValidationError`
if validation fails. Defaults to ``"null_characters_not_allowed"``.

View File

@ -318,7 +318,12 @@ URLs
Validators
~~~~~~~~~~
* ...
* The new :class:`.ProhibitNullCharactersValidator` disallows the null
character in the input of the :class:`~django.forms.CharField` form field
and its subclasses. Null character input was observed from vulnerability
scanning tools. Most databases silently discard null characters, but
psycopg2 2.7+ raises an exception when trying to save a null character to
a char/text field with PostgreSQL.
.. _backwards-incompatible-2.0:

View File

@ -123,3 +123,9 @@ class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
def test_charfield_disabled(self):
f = CharField(disabled=True)
self.assertWidgetRendersTo(f, '<input type="text" name="f" id="id_f" disabled required />')
def test_null_characters_prohibited(self):
f = CharField()
msg = 'Null characters are not allowed.'
with self.assertRaisesMessage(ValidationError, msg):
f.clean('\x00something')

View File

@ -9,11 +9,11 @@ from django.core.files.base import ContentFile
from django.core.validators import (
BaseValidator, DecimalValidator, EmailValidator, FileExtensionValidator,
MaxLengthValidator, MaxValueValidator, MinLengthValidator,
MinValueValidator, RegexValidator, URLValidator, int_list_validator,
validate_comma_separated_integer_list, validate_email,
validate_image_file_extension, validate_integer, validate_ipv4_address,
validate_ipv6_address, validate_ipv46_address, validate_slug,
validate_unicode_slug,
MinValueValidator, ProhibitNullCharactersValidator, RegexValidator,
URLValidator, int_list_validator, validate_comma_separated_integer_list,
validate_email, validate_image_file_extension, validate_integer,
validate_ipv4_address, validate_ipv6_address, validate_ipv46_address,
validate_slug, validate_unicode_slug,
)
from django.test import SimpleTestCase
@ -264,6 +264,10 @@ TEST_DATA = [
(validate_image_file_extension, ContentFile('contents', name='file.PNG'), None),
(validate_image_file_extension, ContentFile('contents', name='file.txt'), ValidationError),
(validate_image_file_extension, ContentFile('contents', name='file'), ValidationError),
(ProhibitNullCharactersValidator(), '\x00something', ValidationError),
(ProhibitNullCharactersValidator(), 'something', None),
(ProhibitNullCharactersValidator(), None, None),
]
@ -488,3 +492,21 @@ class TestValidatorEquality(TestCase):
FileExtensionValidator(['txt']),
FileExtensionValidator(['txt'], message='custom error message')
)
def test_prohibit_null_characters_validator_equality(self):
self.assertEqual(
ProhibitNullCharactersValidator(message='message', code='code'),
ProhibitNullCharactersValidator(message='message', code='code')
)
self.assertEqual(
ProhibitNullCharactersValidator(),
ProhibitNullCharactersValidator()
)
self.assertNotEqual(
ProhibitNullCharactersValidator(message='message1', code='code'),
ProhibitNullCharactersValidator(message='message2', code='code')
)
self.assertNotEqual(
ProhibitNullCharactersValidator(message='message', code='code1'),
ProhibitNullCharactersValidator(message='message', code='code2')
)