!137 Fix CVE-2024-53907 CVE-2024-53908
From: @wk333 Reviewed-by: @cherry530 Signed-off-by: @cherry530
This commit is contained in:
commit
12458c174c
88
CVE-2024-53907.patch
Normal file
88
CVE-2024-53907.patch
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
From 790eb058b0716c536a2f2e8d1c6d5079d776c22b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com>
|
||||||
|
Date: Wed, 13 Nov 2024 15:06:23 +0100
|
||||||
|
Subject: [PATCH] [4.2.x] Fixed CVE-2024-53907 -- Mitigated potential DoS in
|
||||||
|
strip_tags().
|
||||||
|
|
||||||
|
Origin: https://github.com/django/django/commit/790eb058b0716c536a2f2e8d1c6d5079d776c22b
|
||||||
|
|
||||||
|
Thanks to jiangniao for the report, and Shai Berger and Natalia Bidart
|
||||||
|
for the reviews.
|
||||||
|
---
|
||||||
|
django/utils/html.py | 10 ++++++++--
|
||||||
|
tests/utils_tests/test_html.py | 7 +++++++
|
||||||
|
3 files changed, 31 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/django/utils/html.py b/django/utils/html.py
|
||||||
|
index df38c2051994..a3a7238cba44 100644
|
||||||
|
--- a/django/utils/html.py
|
||||||
|
+++ b/django/utils/html.py
|
||||||
|
@@ -6,6 +6,7 @@
|
||||||
|
from html.parser import HTMLParser
|
||||||
|
from urllib.parse import parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit
|
||||||
|
|
||||||
|
+from django.core.exceptions import SuspiciousOperation
|
||||||
|
from django.utils.encoding import punycode
|
||||||
|
from django.utils.functional import Promise, cached_property, keep_lazy, keep_lazy_text
|
||||||
|
from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS
|
||||||
|
@@ -14,6 +15,7 @@
|
||||||
|
from django.utils.text import normalize_newlines
|
||||||
|
|
||||||
|
MAX_URL_LENGTH = 2048
|
||||||
|
+MAX_STRIP_TAGS_DEPTH = 50
|
||||||
|
|
||||||
|
|
||||||
|
@keep_lazy(SafeString)
|
||||||
|
@@ -172,15 +174,19 @@ def _strip_once(value):
|
||||||
|
@keep_lazy_text
|
||||||
|
def strip_tags(value):
|
||||||
|
"""Return the given HTML with all tags stripped."""
|
||||||
|
- # Note: in typical case this loop executes _strip_once once. Loop condition
|
||||||
|
- # is redundant, but helps to reduce number of executions of _strip_once.
|
||||||
|
value = str(value)
|
||||||
|
+ # Note: in typical case this loop executes _strip_once twice (the second
|
||||||
|
+ # execution does not remove any more tags).
|
||||||
|
+ strip_tags_depth = 0
|
||||||
|
while "<" in value and ">" in value:
|
||||||
|
+ if strip_tags_depth >= MAX_STRIP_TAGS_DEPTH:
|
||||||
|
+ raise SuspiciousOperation
|
||||||
|
new_value = _strip_once(value)
|
||||||
|
if value.count("<") == new_value.count("<"):
|
||||||
|
# _strip_once wasn't able to detect more tags.
|
||||||
|
break
|
||||||
|
value = new_value
|
||||||
|
+ strip_tags_depth += 1
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py
|
||||||
|
index 7ff5020fb6d3..579bb2a1e359 100644
|
||||||
|
--- a/tests/utils_tests/test_html.py
|
||||||
|
+++ b/tests/utils_tests/test_html.py
|
||||||
|
@@ -1,6 +1,7 @@
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
+from django.core.exceptions import SuspiciousOperation
|
||||||
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
from django.test import SimpleTestCase
|
||||||
|
from django.utils.functional import lazystr
|
||||||
|
@@ -113,12 +114,18 @@ def test_strip_tags(self):
|
||||||
|
("<script>alert()</script>&h", "alert()h"),
|
||||||
|
("><!" + ("&" * 16000) + "D", "><!" + ("&" * 16000) + "D"),
|
||||||
|
("X<<<<br>br>br>br>X", "XX"),
|
||||||
|
+ ("<" * 50 + "a>" * 50, ""),
|
||||||
|
)
|
||||||
|
for value, output in items:
|
||||||
|
with self.subTest(value=value, output=output):
|
||||||
|
self.check_output(strip_tags, value, output)
|
||||||
|
self.check_output(strip_tags, lazystr(value), output)
|
||||||
|
|
||||||
|
+ def test_strip_tags_suspicious_operation(self):
|
||||||
|
+ value = "<" * 51 + "a>" * 51, "<a>"
|
||||||
|
+ with self.assertRaises(SuspiciousOperation):
|
||||||
|
+ strip_tags(value)
|
||||||
|
+
|
||||||
|
def test_strip_tags_files(self):
|
||||||
|
# Test with more lengthy content (also catching performance regressions)
|
||||||
|
for filename in ("strip_tags1.html", "strip_tags2.txt"):
|
||||||
145
CVE-2024-53908.patch
Normal file
145
CVE-2024-53908.patch
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
From 7376bcbf508883282ffcc0f0fac5cf0ed2d6cbc5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Simon Charette <charette.s@gmail.com>
|
||||||
|
Date: Fri, 8 Nov 2024 21:27:31 -0500
|
||||||
|
Subject: [PATCH] [4.2.x] Fixed CVE-2024-53908 -- Prevented SQL injections in
|
||||||
|
direct HasKeyLookup usage on Oracle.
|
||||||
|
|
||||||
|
Origin: https://github.com/django/django/commit/7376bcbf508883282ffcc0f0fac5cf0ed2d6cbc5
|
||||||
|
|
||||||
|
Thanks Seokchan Yoon for the report, and Mariusz Felisiak and Sarah
|
||||||
|
Boyce for the reviews.
|
||||||
|
---
|
||||||
|
django/db/models/fields/json.py | 53 ++++++++++++++++++----------
|
||||||
|
tests/model_fields/test_jsonfield.py | 9 +++++
|
||||||
|
3 files changed, 53 insertions(+), 18 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/django/db/models/fields/json.py b/django/db/models/fields/json.py
|
||||||
|
index b7cde157c4fa..b9c6ff1752b9 100644
|
||||||
|
--- a/django/db/models/fields/json.py
|
||||||
|
+++ b/django/db/models/fields/json.py
|
||||||
|
@@ -216,20 +216,18 @@ def compile_json_path_final_key(self, key_transform):
|
||||||
|
# Compile the final key without interpreting ints as array elements.
|
||||||
|
return ".%s" % json.dumps(key_transform)
|
||||||
|
|
||||||
|
- def as_sql(self, compiler, connection, template=None):
|
||||||
|
+ def _as_sql_parts(self, compiler, connection):
|
||||||
|
# Process JSON path from the left-hand side.
|
||||||
|
if isinstance(self.lhs, KeyTransform):
|
||||||
|
- lhs, lhs_params, lhs_key_transforms = self.lhs.preprocess_lhs(
|
||||||
|
+ lhs_sql, lhs_params, lhs_key_transforms = self.lhs.preprocess_lhs(
|
||||||
|
compiler, connection
|
||||||
|
)
|
||||||
|
lhs_json_path = compile_json_path(lhs_key_transforms)
|
||||||
|
else:
|
||||||
|
- lhs, lhs_params = self.process_lhs(compiler, connection)
|
||||||
|
+ lhs_sql, lhs_params = self.process_lhs(compiler, connection)
|
||||||
|
lhs_json_path = "$"
|
||||||
|
- sql = template % lhs
|
||||||
|
# Process JSON path from the right-hand side.
|
||||||
|
rhs = self.rhs
|
||||||
|
- rhs_params = []
|
||||||
|
if not isinstance(rhs, (list, tuple)):
|
||||||
|
rhs = [rhs]
|
||||||
|
for key in rhs:
|
||||||
|
@@ -240,24 +238,43 @@ def as_sql(self, compiler, connection, template=None):
|
||||||
|
*rhs_key_transforms, final_key = rhs_key_transforms
|
||||||
|
rhs_json_path = compile_json_path(rhs_key_transforms, include_root=False)
|
||||||
|
rhs_json_path += self.compile_json_path_final_key(final_key)
|
||||||
|
- rhs_params.append(lhs_json_path + rhs_json_path)
|
||||||
|
+ yield lhs_sql, lhs_params, lhs_json_path + rhs_json_path
|
||||||
|
+
|
||||||
|
+ def _combine_sql_parts(self, parts):
|
||||||
|
# Add condition for each key.
|
||||||
|
if self.logical_operator:
|
||||||
|
- sql = "(%s)" % self.logical_operator.join([sql] * len(rhs_params))
|
||||||
|
- return sql, tuple(lhs_params) + tuple(rhs_params)
|
||||||
|
+ return "(%s)" % self.logical_operator.join(parts)
|
||||||
|
+ return "".join(parts)
|
||||||
|
+
|
||||||
|
+ def as_sql(self, compiler, connection, template=None):
|
||||||
|
+ sql_parts = []
|
||||||
|
+ params = []
|
||||||
|
+ for lhs_sql, lhs_params, rhs_json_path in self._as_sql_parts(
|
||||||
|
+ compiler, connection
|
||||||
|
+ ):
|
||||||
|
+ sql_parts.append(template % (lhs_sql, "%s"))
|
||||||
|
+ params.extend(lhs_params + [rhs_json_path])
|
||||||
|
+ return self._combine_sql_parts(sql_parts), tuple(params)
|
||||||
|
|
||||||
|
def as_mysql(self, compiler, connection):
|
||||||
|
return self.as_sql(
|
||||||
|
- compiler, connection, template="JSON_CONTAINS_PATH(%s, 'one', %%s)"
|
||||||
|
+ compiler, connection, template="JSON_CONTAINS_PATH(%s, 'one', %s)"
|
||||||
|
)
|
||||||
|
|
||||||
|
def as_oracle(self, compiler, connection):
|
||||||
|
- sql, params = self.as_sql(
|
||||||
|
- compiler, connection, template="JSON_EXISTS(%s, '%%s')"
|
||||||
|
- )
|
||||||
|
- # Add paths directly into SQL because path expressions cannot be passed
|
||||||
|
- # as bind variables on Oracle.
|
||||||
|
- return sql % tuple(params), []
|
||||||
|
+ template = "JSON_EXISTS(%s, '%s')"
|
||||||
|
+ sql_parts = []
|
||||||
|
+ params = []
|
||||||
|
+ for lhs_sql, lhs_params, rhs_json_path in self._as_sql_parts(
|
||||||
|
+ compiler, connection
|
||||||
|
+ ):
|
||||||
|
+ # Add right-hand-side directly into SQL because it cannot be passed
|
||||||
|
+ # as bind variables to JSON_EXISTS. It might result in invalid
|
||||||
|
+ # queries but it is assumed that it cannot be evaded because the
|
||||||
|
+ # path is JSON serialized.
|
||||||
|
+ sql_parts.append(template % (lhs_sql, rhs_json_path))
|
||||||
|
+ params.extend(lhs_params)
|
||||||
|
+ return self._combine_sql_parts(sql_parts), tuple(params)
|
||||||
|
|
||||||
|
def as_postgresql(self, compiler, connection):
|
||||||
|
if isinstance(self.rhs, KeyTransform):
|
||||||
|
@@ -269,7 +286,7 @@ def as_postgresql(self, compiler, connection):
|
||||||
|
|
||||||
|
def as_sqlite(self, compiler, connection):
|
||||||
|
return self.as_sql(
|
||||||
|
- compiler, connection, template="JSON_TYPE(%s, %%s) IS NOT NULL"
|
||||||
|
+ compiler, connection, template="JSON_TYPE(%s, %s) IS NOT NULL"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -467,9 +484,9 @@ def as_oracle(self, compiler, connection):
|
||||||
|
return "(NOT %s OR %s IS NULL)" % (sql, lhs), tuple(params) + tuple(lhs_params)
|
||||||
|
|
||||||
|
def as_sqlite(self, compiler, connection):
|
||||||
|
- template = "JSON_TYPE(%s, %%s) IS NULL"
|
||||||
|
+ template = "JSON_TYPE(%s, %s) IS NULL"
|
||||||
|
if not self.rhs:
|
||||||
|
- template = "JSON_TYPE(%s, %%s) IS NOT NULL"
|
||||||
|
+ template = "JSON_TYPE(%s, %s) IS NOT NULL"
|
||||||
|
return HasKeyOrArrayIndex(self.lhs.lhs, self.lhs.key_name).as_sql(
|
||||||
|
compiler,
|
||||||
|
connection,
|
||||||
|
diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py
|
||||||
|
index 4a1cc075b4c4..4c8d14bf9a17 100644
|
||||||
|
--- a/tests/model_fields/test_jsonfield.py
|
||||||
|
+++ b/tests/model_fields/test_jsonfield.py
|
||||||
|
@@ -29,6 +29,7 @@
|
||||||
|
from django.db.models.expressions import RawSQL
|
||||||
|
from django.db.models.fields.json import (
|
||||||
|
KT,
|
||||||
|
+ HasKey,
|
||||||
|
KeyTextTransform,
|
||||||
|
KeyTransform,
|
||||||
|
KeyTransformFactory,
|
||||||
|
@@ -607,6 +608,14 @@ def test_has_key_deep(self):
|
||||||
|
[expected],
|
||||||
|
)
|
||||||
|
|
||||||
|
+ def test_has_key_literal_lookup(self):
|
||||||
|
+ self.assertSequenceEqual(
|
||||||
|
+ NullableJSONModel.objects.filter(
|
||||||
|
+ HasKey(Value({"foo": "bar"}, JSONField()), "foo")
|
||||||
|
+ ).order_by("id"),
|
||||||
|
+ self.objs,
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
def test_has_key_list(self):
|
||||||
|
obj = NullableJSONModel.objects.create(value=[{"a": 1}, {"b": "x"}])
|
||||||
|
tests = [
|
||||||
@ -1,13 +1,15 @@
|
|||||||
%global _empty_manifest_terminate_build 0
|
%global _empty_manifest_terminate_build 0
|
||||||
Name: python-django
|
Name: python-django
|
||||||
Version: 4.2.15
|
Version: 4.2.15
|
||||||
Release: 2
|
Release: 3
|
||||||
Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
|
Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
|
||||||
License: Apache-2.0 and Python-2.0 and BSD-3-Clause
|
License: Apache-2.0 and Python-2.0 and BSD-3-Clause
|
||||||
URL: https://www.djangoproject.com/
|
URL: https://www.djangoproject.com/
|
||||||
Source0: https://files.pythonhosted.org/packages/source/d/Django/Django-%{version}.tar.gz
|
Source0: https://files.pythonhosted.org/packages/source/d/Django/Django-%{version}.tar.gz
|
||||||
Patch0: CVE-2024-45230.patch
|
Patch0: CVE-2024-45230.patch
|
||||||
Patch1: CVE-2024-45231.patch
|
Patch1: CVE-2024-45231.patch
|
||||||
|
Patch2: CVE-2024-53907.patch
|
||||||
|
Patch3: CVE-2024-53908.patch
|
||||||
|
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
%description
|
%description
|
||||||
@ -74,6 +76,9 @@ mv %{buildroot}/doclist.lst .
|
|||||||
%{_docdir}/*
|
%{_docdir}/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Dec 09 2024 wangkai <13474090681@163.com> - 4.2.15-3
|
||||||
|
- Fix CVE-2024-53907 CVE-2024-53908
|
||||||
|
|
||||||
* Thu Oct 10 2024 zhangxianting <zhangxianting@uniontech.com> - 4.2.15-2
|
* Thu Oct 10 2024 zhangxianting <zhangxianting@uniontech.com> - 4.2.15-2
|
||||||
- Fix CVE-2024-45230 CVE-2024-45231
|
- Fix CVE-2024-45230 CVE-2024-45231
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user