1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
From: Chris Lamb <lamby@debian.org>
Date: Thu, 8 Aug 2019 10:35:56 +0100
Subject: CVE-2019-14234
Backported from
<https://github.com/django/django/commit/ed682a24fca774818542757651bfba576c3fc3ef>
---
django/contrib/postgres/fields/hstore.py | 2 +-
django/contrib/postgres/fields/jsonb.py | 8 +++-----
tests/postgres_tests/test_hstore.py | 14 ++++++++++++++
tests/postgres_tests/test_json.py | 15 ++++++++++++++-
4 files changed, 32 insertions(+), 7 deletions(-)
diff --git a/django/contrib/postgres/fields/hstore.py b/django/contrib/postgres/fields/hstore.py
index 8322d81..6d6f542 100644
--- a/django/contrib/postgres/fields/hstore.py
+++ b/django/contrib/postgres/fields/hstore.py
@@ -85,7 +85,7 @@ class KeyTransform(Transform):
def as_sql(self, compiler, connection):
lhs, params = compiler.compile(self.lhs)
- return "(%s -> '%s')" % (lhs, self.key_name), params
+ return '(%s -> %%s)' % lhs, [self.key_name] + params
class KeyTransformFactory(object):
diff --git a/django/contrib/postgres/fields/jsonb.py b/django/contrib/postgres/fields/jsonb.py
index ae83d9e..6d30b7a 100644
--- a/django/contrib/postgres/fields/jsonb.py
+++ b/django/contrib/postgres/fields/jsonb.py
@@ -75,12 +75,10 @@ class KeyTransform(Transform):
if len(key_transforms) > 1:
return "{} #> %s".format(lhs), [key_transforms] + params
try:
- int(self.key_name)
+ lookup = int(self.key_name)
except ValueError:
- lookup = "'%s'" % self.key_name
- else:
- lookup = "%s" % self.key_name
- return "%s -> %s" % (lhs, lookup), params
+ lookup = self.key_name
+ return '(%s %s %%s)' % (lhs, self.operator), [lookup] + params
class KeyTransformFactory(object):
diff --git a/tests/postgres_tests/test_hstore.py b/tests/postgres_tests/test_hstore.py
index 0afa630..fbcd32c 100644
--- a/tests/postgres_tests/test_hstore.py
+++ b/tests/postgres_tests/test_hstore.py
@@ -3,8 +3,10 @@ from __future__ import unicode_literals
import json
+from django.db import connection
from django.core import exceptions, serializers
from django.forms import Form
+from django.test.utils import CaptureQueriesContext
from . import PostgreSQLTestCase
from .models import HStoreModel
@@ -163,6 +165,18 @@ class TestQuerying(PostgreSQLTestCase):
self.objs[:2]
)
+ def test_key_sql_injection(self):
+ with CaptureQueriesContext(connection) as queries:
+ self.assertFalse(
+ HStoreModel.objects.filter(**{
+ "field__test' = 'a') OR 1 = 1 OR ('d": 'x',
+ }).exists()
+ )
+ self.assertIn(
+ """."field" -> 'test'' = ''a'') OR 1 = 1 OR (''d') = 'x' """,
+ queries[0]['sql'],
+ )
+
class TestSerialization(PostgreSQLTestCase):
test_data = ('[{"fields": {"field": "{\\"a\\": \\"b\\"}"}, '
diff --git a/tests/postgres_tests/test_json.py b/tests/postgres_tests/test_json.py
index 1978552..216fe77 100644
--- a/tests/postgres_tests/test_json.py
+++ b/tests/postgres_tests/test_json.py
@@ -1,10 +1,11 @@
import datetime
import unittest
-from django.core import exceptions, serializers
from django.db import connection
+from django.core import exceptions, serializers
from django.forms import CharField, Form
from django.test import TestCase
+from django.test.utils import CaptureQueriesContext
from django.utils.html import escape
from . import PostgreSQLTestCase
@@ -236,6 +237,18 @@ class TestValidation(PostgreSQLTestCase):
self.assertEqual(cm.exception.code, 'invalid')
self.assertEqual(cm.exception.message % cm.exception.params, "Value must be valid JSON.")
+ def test_key_sql_injection(self):
+ with CaptureQueriesContext(connection) as queries:
+ self.assertFalse(
+ JSONModel.objects.filter(**{
+ """field__test' = '"a"') OR 1 = 1 OR ('d""": 'x',
+ }).exists()
+ )
+ self.assertIn(
+ """."field" -> 'test'' = ''"a"'') OR 1 = 1 OR (''d') = '"x"' """,
+ queries[0]['sql'],
+ )
+
class TestFormField(PostgreSQLTestCase):
|