Fixed CVE-2020-7471 -- Properly escaped StringAgg(delimiter) parameter.

This commit is contained in:
Simon Charette 2019-12-31 12:46:06 -05:00 committed by Carlton Gibson
parent 6b178a3e93
commit eb31d84532
7 changed files with 45 additions and 5 deletions

View File

@ -1,4 +1,5 @@
from django.contrib.postgres.fields import ArrayField, JSONField from django.contrib.postgres.fields import ArrayField, JSONField
from django.db.models import Value
from django.db.models.aggregates import Aggregate from django.db.models.aggregates import Aggregate
from .mixins import OrderableAggMixin from .mixins import OrderableAggMixin
@ -51,11 +52,12 @@ class JSONBAgg(Aggregate):
class StringAgg(OrderableAggMixin, Aggregate): class StringAgg(OrderableAggMixin, Aggregate):
function = 'STRING_AGG' function = 'STRING_AGG'
template = "%(function)s(%(distinct)s%(expressions)s, '%(delimiter)s'%(ordering)s)" template = '%(function)s(%(distinct)s%(expressions)s %(ordering)s)'
allow_distinct = True allow_distinct = True
def __init__(self, expression, delimiter, **extra): def __init__(self, expression, delimiter, **extra):
super().__init__(expression, delimiter=delimiter, **extra) delimiter_expr = Value(str(delimiter))
super().__init__(expression, delimiter_expr, **extra)
def convert_value(self, value, expression, connection): def convert_value(self, value, expression, connection):
if not value: if not value:

View File

@ -3,7 +3,7 @@ from django.db.models.expressions import F, OrderBy
class OrderableAggMixin: class OrderableAggMixin:
def __init__(self, expression, ordering=(), **extra): def __init__(self, *expressions, ordering=(), **extra):
if not isinstance(ordering, (list, tuple)): if not isinstance(ordering, (list, tuple)):
ordering = [ordering] ordering = [ordering]
ordering = ordering or [] ordering = ordering or []
@ -12,7 +12,7 @@ class OrderableAggMixin:
(OrderBy(F(o[1:]), descending=True) if isinstance(o, str) and o[0] == '-' else o) (OrderBy(F(o[1:]), descending=True) if isinstance(o, str) and o[0] == '-' else o)
for o in ordering for o in ordering
) )
super().__init__(expression, **extra) super().__init__(*expressions, **extra)
self.ordering = self._parse_expressions(*ordering) self.ordering = self._parse_expressions(*ordering)
def resolve_expression(self, *args, **kwargs): def resolve_expression(self, *args, **kwargs):

13
docs/releases/1.11.28.txt Normal file
View File

@ -0,0 +1,13 @@
============================
Django 1.11.28 release notes
============================
*February 3, 2020*
Django 1.11.28 fixes a security issue in 1.11.27.
CVE-2020-7471: Potential SQL injection via ``StringAgg(delimiter)``
===================================================================
:class:`~django.contrib.postgres.aggregates.StringAgg` aggregation function was
subject to SQL injection, using a suitably crafted ``delimiter``.

13
docs/releases/2.2.10.txt Normal file
View File

@ -0,0 +1,13 @@
===========================
Django 2.2.10 release notes
===========================
*February 3, 2020*
Django 2.2.10 fixes a security issue in 2.2.9.
CVE-2020-7471: Potential SQL injection via ``StringAgg(delimiter)``
===================================================================
:class:`~django.contrib.postgres.aggregates.StringAgg` aggregation function was
subject to SQL injection, using a suitably crafted ``delimiter``.

View File

@ -4,7 +4,13 @@ Django 3.0.3 release notes
*Expected February 3, 2020* *Expected February 3, 2020*
Django 3.0.3 fixes several bugs in 3.0.2. Django 3.0.3 fixes a security issue and several bugs in 3.0.2.
CVE-2020-7471: Potential SQL injection via ``StringAgg(delimiter)``
===================================================================
:class:`~django.contrib.postgres.aggregates.StringAgg` aggregation function was
subject to SQL injection, using a suitably crafted ``delimiter``.
Bugfixes Bugfixes
======== ========

View File

@ -42,6 +42,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
2.2.10
2.2.9 2.2.9
2.2.8 2.2.8
2.2.7 2.2.7
@ -100,6 +101,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
1.11.28
1.11.27 1.11.27
1.11.26 1.11.26
1.11.25 1.11.25

View File

@ -169,6 +169,10 @@ class TestGeneralAggregate(PostgreSQLTestCase):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field')) AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field'))
def test_string_agg_delimiter_escaping(self):
values = AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field', delimiter="'"))
self.assertEqual(values, {'stringagg': "Foo1'Foo2'Foo4'Foo3"})
def test_string_agg_charfield(self): def test_string_agg_charfield(self):
values = AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field', delimiter=';')) values = AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field', delimiter=';'))
self.assertEqual(values, {'stringagg': 'Foo1;Foo2;Foo4;Foo3'}) self.assertEqual(values, {'stringagg': 'Foo1;Foo2;Foo4;Foo3'})