!33 [sync] PR-32: Fix CVE-2024-27306
From: @openeuler-sync-bot Reviewed-by: @caodongxia Signed-off-by: @caodongxia
This commit is contained in:
commit
7f381c5cf3
242
CVE-2024-27306.patch
Normal file
242
CVE-2024-27306.patch
Normal file
@ -0,0 +1,242 @@
|
||||
From 28335525d1eac015a7e7584137678cbb6ff19397 Mon Sep 17 00:00:00 2001
|
||||
From: Sam Bull <git@sambull.org>
|
||||
Date: Thu, 11 Apr 2024 15:54:45 +0100
|
||||
Subject: [PATCH] Escape filenames and paths in HTML when generating index
|
||||
pages (#8317) (#8319)
|
||||
|
||||
Co-authored-by: J. Nick Koston <nick@koston.org>
|
||||
(cherry picked from commit ffbc43233209df302863712b511a11bdb6001b0f)
|
||||
---
|
||||
CHANGES/8317.bugfix.rst | 1 +
|
||||
aiohttp/web_urldispatcher.py | 12 ++--
|
||||
tests/test_web_urldispatcher.py | 124 ++++++++++++++++++++++++++++----
|
||||
3 files changed, 118 insertions(+), 19 deletions(-)
|
||||
create mode 100644 CHANGES/8317.bugfix.rst
|
||||
|
||||
diff --git a/CHANGES/8317.bugfix.rst b/CHANGES/8317.bugfix.rst
|
||||
new file mode 100644
|
||||
index 0000000000..b24ef2aeb8
|
||||
--- /dev/null
|
||||
+++ b/CHANGES/8317.bugfix.rst
|
||||
@@ -0,0 +1 @@
|
||||
+Escaped filenames in static view -- by :user:`bdraco`.
|
||||
diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py
|
||||
index 9969653344..954291f644 100644
|
||||
--- a/aiohttp/web_urldispatcher.py
|
||||
+++ b/aiohttp/web_urldispatcher.py
|
||||
@@ -1,7 +1,9 @@
|
||||
import abc
|
||||
import asyncio
|
||||
import base64
|
||||
+import functools
|
||||
import hashlib
|
||||
+import html
|
||||
import inspect
|
||||
import keyword
|
||||
import os
|
||||
@@ -90,6 +92,8 @@
|
||||
_ExpectHandler = Callable[[Request], Awaitable[Optional[StreamResponse]]]
|
||||
_Resolve = Tuple[Optional["UrlMappingMatchInfo"], Set[str]]
|
||||
|
||||
+html_escape = functools.partial(html.escape, quote=True)
|
||||
+
|
||||
|
||||
class _InfoDict(TypedDict, total=False):
|
||||
path: str
|
||||
@@ -708,7 +712,7 @@ def _directory_as_html(self, filepath: Path) -> str:
|
||||
assert filepath.is_dir()
|
||||
|
||||
relative_path_to_dir = filepath.relative_to(self._directory).as_posix()
|
||||
- index_of = f"Index of /{relative_path_to_dir}"
|
||||
+ index_of = f"Index of /{html_escape(relative_path_to_dir)}"
|
||||
h1 = f"<h1>{index_of}</h1>"
|
||||
|
||||
index_list = []
|
||||
@@ -716,7 +720,7 @@ def _directory_as_html(self, filepath: Path) -> str:
|
||||
for _file in sorted(dir_index):
|
||||
# show file url as relative to static path
|
||||
rel_path = _file.relative_to(self._directory).as_posix()
|
||||
- file_url = self._prefix + "/" + rel_path
|
||||
+ quoted_file_url = _quote_path(f"{self._prefix}/{rel_path}")
|
||||
|
||||
# if file is a directory, add '/' to the end of the name
|
||||
if _file.is_dir():
|
||||
@@ -725,9 +729,7 @@ def _directory_as_html(self, filepath: Path) -> str:
|
||||
file_name = _file.name
|
||||
|
||||
index_list.append(
|
||||
- '<li><a href="{url}">{name}</a></li>'.format(
|
||||
- url=file_url, name=file_name
|
||||
- )
|
||||
+ f'<li><a href="{quoted_file_url}">{html_escape(file_name)}</a></li>'
|
||||
)
|
||||
ul = "<ul>\n{}\n</ul>".format("\n".join(index_list))
|
||||
body = f"<body>\n{h1}\n{ul}\n</body>"
|
||||
diff --git a/tests/test_web_urldispatcher.py b/tests/test_web_urldispatcher.py
|
||||
index 76e533e473..0441890c10 100644
|
||||
--- a/tests/test_web_urldispatcher.py
|
||||
+++ b/tests/test_web_urldispatcher.py
|
||||
@@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
import functools
|
||||
import pathlib
|
||||
+import sys
|
||||
from typing import Optional
|
||||
from unittest import mock
|
||||
from unittest.mock import MagicMock
|
||||
@@ -14,31 +15,38 @@
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
- "show_index,status,prefix,data",
|
||||
+ "show_index,status,prefix,request_path,data",
|
||||
[
|
||||
- pytest.param(False, 403, "/", None, id="index_forbidden"),
|
||||
+ pytest.param(False, 403, "/", "/", None, id="index_forbidden"),
|
||||
pytest.param(
|
||||
True,
|
||||
200,
|
||||
"/",
|
||||
- b"<html>\n<head>\n<title>Index of /.</title>\n"
|
||||
- b"</head>\n<body>\n<h1>Index of /.</h1>\n<ul>\n"
|
||||
- b'<li><a href="/my_dir">my_dir/</a></li>\n'
|
||||
- b'<li><a href="/my_file">my_file</a></li>\n'
|
||||
- b"</ul>\n</body>\n</html>",
|
||||
- id="index_root",
|
||||
+ "/",
|
||||
+ b"<html>\n<head>\n<title>Index of /.</title>\n</head>\n<body>\n<h1>Index of"
|
||||
+ b' /.</h1>\n<ul>\n<li><a href="/my_dir">my_dir/</a></li>\n<li><a href="/my_file">'
|
||||
+ b"my_file</a></li>\n</ul>\n</body>\n</html>",
|
||||
),
|
||||
pytest.param(
|
||||
True,
|
||||
200,
|
||||
"/static",
|
||||
- b"<html>\n<head>\n<title>Index of /.</title>\n"
|
||||
- b"</head>\n<body>\n<h1>Index of /.</h1>\n<ul>\n"
|
||||
- b'<li><a href="/static/my_dir">my_dir/</a></li>\n'
|
||||
- b'<li><a href="/static/my_file">my_file</a></li>\n'
|
||||
- b"</ul>\n</body>\n</html>",
|
||||
+ "/static",
|
||||
+ b"<html>\n<head>\n<title>Index of /.</title>\n</head>\n<body>\n<h1>Index of"
|
||||
+ b' /.</h1>\n<ul>\n<li><a href="/static/my_dir">my_dir/</a></li>\n<li><a href="'
|
||||
+ b'/static/my_file">my_file</a></li>\n</ul>\n</body>\n</html>',
|
||||
id="index_static",
|
||||
),
|
||||
+ pytest.param(
|
||||
+ True,
|
||||
+ 200,
|
||||
+ "/static",
|
||||
+ "/static/my_dir",
|
||||
+ b"<html>\n<head>\n<title>Index of /my_dir</title>\n</head>\n<body>\n<h1>"
|
||||
+ b'Index of /my_dir</h1>\n<ul>\n<li><a href="/static/my_dir/my_file_in_dir">'
|
||||
+ b"my_file_in_dir</a></li>\n</ul>\n</body>\n</html>",
|
||||
+ id="index_subdir",
|
||||
+ ),
|
||||
],
|
||||
)
|
||||
async def test_access_root_of_static_handler(
|
||||
@@ -47,6 +55,7 @@ async def test_access_root_of_static_handler(
|
||||
show_index: bool,
|
||||
status: int,
|
||||
prefix: str,
|
||||
+ request_path: str,
|
||||
data: Optional[bytes],
|
||||
) -> None:
|
||||
# Tests the operation of static file server.
|
||||
@@ -72,7 +81,94 @@ async def test_access_root_of_static_handler(
|
||||
client = await aiohttp_client(app)
|
||||
|
||||
# Request the root of the static directory.
|
||||
- async with await client.get(prefix) as r:
|
||||
+ async with await client.get(request_path) as r:
|
||||
+ assert r.status == status
|
||||
+
|
||||
+ if data:
|
||||
+ assert r.headers["Content-Type"] == "text/html; charset=utf-8"
|
||||
+ read_ = await r.read()
|
||||
+ assert read_ == data
|
||||
+
|
||||
+
|
||||
+@pytest.mark.internal # Dependent on filesystem
|
||||
+@pytest.mark.skipif(
|
||||
+ not sys.platform.startswith("linux"),
|
||||
+ reason="Invalid filenames on some filesystems (like Windows)",
|
||||
+)
|
||||
+@pytest.mark.parametrize(
|
||||
+ "show_index,status,prefix,request_path,data",
|
||||
+ [
|
||||
+ pytest.param(False, 403, "/", "/", None, id="index_forbidden"),
|
||||
+ pytest.param(
|
||||
+ True,
|
||||
+ 200,
|
||||
+ "/",
|
||||
+ "/",
|
||||
+ b"<html>\n<head>\n<title>Index of /.</title>\n</head>\n<body>\n<h1>Index of"
|
||||
+ b' /.</h1>\n<ul>\n<li><a href="/%3Cimg%20src=0%20onerror=alert(1)%3E.dir">&l'
|
||||
+ b't;img src=0 onerror=alert(1)>.dir/</a></li>\n<li><a href="/%3Cimg%20sr'
|
||||
+ b'c=0%20onerror=alert(1)%3E.txt"><img src=0 onerror=alert(1)>.txt</a></l'
|
||||
+ b"i>\n</ul>\n</body>\n</html>",
|
||||
+ ),
|
||||
+ pytest.param(
|
||||
+ True,
|
||||
+ 200,
|
||||
+ "/static",
|
||||
+ "/static",
|
||||
+ b"<html>\n<head>\n<title>Index of /.</title>\n</head>\n<body>\n<h1>Index of"
|
||||
+ b' /.</h1>\n<ul>\n<li><a href="/static/%3Cimg%20src=0%20onerror=alert(1)%3E.'
|
||||
+ b'dir"><img src=0 onerror=alert(1)>.dir/</a></li>\n<li><a href="/stat'
|
||||
+ b'ic/%3Cimg%20src=0%20onerror=alert(1)%3E.txt"><img src=0 onerror=alert(1)&'
|
||||
+ b"gt;.txt</a></li>\n</ul>\n</body>\n</html>",
|
||||
+ id="index_static",
|
||||
+ ),
|
||||
+ pytest.param(
|
||||
+ True,
|
||||
+ 200,
|
||||
+ "/static",
|
||||
+ "/static/<img src=0 onerror=alert(1)>.dir",
|
||||
+ b"<html>\n<head>\n<title>Index of /<img src=0 onerror=alert(1)>.dir</t"
|
||||
+ b"itle>\n</head>\n<body>\n<h1>Index of /<img src=0 onerror=alert(1)>.di"
|
||||
+ b'r</h1>\n<ul>\n<li><a href="/static/%3Cimg%20src=0%20onerror=alert(1)%3E.di'
|
||||
+ b'r/my_file_in_dir">my_file_in_dir</a></li>\n</ul>\n</body>\n</html>',
|
||||
+ id="index_subdir",
|
||||
+ ),
|
||||
+ ],
|
||||
+)
|
||||
+async def test_access_root_of_static_handler_xss(
|
||||
+ tmp_path: pathlib.Path,
|
||||
+ aiohttp_client: AiohttpClient,
|
||||
+ show_index: bool,
|
||||
+ status: int,
|
||||
+ prefix: str,
|
||||
+ request_path: str,
|
||||
+ data: Optional[bytes],
|
||||
+) -> None:
|
||||
+ # Tests the operation of static file server.
|
||||
+ # Try to access the root of static file server, and make
|
||||
+ # sure that correct HTTP statuses are returned depending if we directory
|
||||
+ # index should be shown or not.
|
||||
+ # Ensure that html in file names is escaped.
|
||||
+ # Ensure that links are url quoted.
|
||||
+ my_file = tmp_path / "<img src=0 onerror=alert(1)>.txt"
|
||||
+ my_dir = tmp_path / "<img src=0 onerror=alert(1)>.dir"
|
||||
+ my_dir.mkdir()
|
||||
+ my_file_in_dir = my_dir / "my_file_in_dir"
|
||||
+
|
||||
+ with my_file.open("w") as fw:
|
||||
+ fw.write("hello")
|
||||
+
|
||||
+ with my_file_in_dir.open("w") as fw:
|
||||
+ fw.write("world")
|
||||
+
|
||||
+ app = web.Application()
|
||||
+
|
||||
+ # Register global static route:
|
||||
+ app.router.add_static(prefix, str(tmp_path), show_index=show_index)
|
||||
+ client = await aiohttp_client(app)
|
||||
+
|
||||
+ # Request the root of the static directory.
|
||||
+ async with await client.get(request_path) as r:
|
||||
assert r.status == status
|
||||
|
||||
if data:
|
||||
@ -1,11 +1,13 @@
|
||||
%global _empty_manifest_terminate_build 0
|
||||
Name: python-aiohttp
|
||||
Version: 3.9.3
|
||||
Release: 1
|
||||
Release: 2
|
||||
Summary: Async http client/server framework (asyncio)
|
||||
License: Apache 2
|
||||
URL: https://github.com/aio-libs/aiohttp
|
||||
Source0: %{pypi_source aiohttp}
|
||||
# https://github.com/aio-libs/aiohttp/commit/28335525d1eac015a7e7584137678cbb6ff19397
|
||||
Patch0: CVE-2024-27306.patch
|
||||
|
||||
Requires: python3-attrs
|
||||
Requires: python3-charset-normalizer
|
||||
@ -81,6 +83,9 @@ mv %{buildroot}/doclist.lst .
|
||||
%{_docdir}/*
|
||||
|
||||
%changelog
|
||||
* Mon Apr 22 2024 yaoxin <yao_xin001@hoperun.com> - 3.9.3-2
|
||||
- Fix CVE-2024-27306
|
||||
|
||||
* Wed Jan 31 2024 yaoxin <yao_xin001@hoperun.com> - 3.9.3-1
|
||||
- Upgrade to 3.9.3 for fix CVE-2024-23334 and CVE-2024-23829
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user