Prevent directory traversion with static files (#2495)

Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Co-authored-by: Zhiwei Liang <zhi.wei.liang@outlook.com>
This commit is contained in:
Néstor Pérez
2022-07-28 16:45:45 +10:00
committed by GitHub
parent 312ab298fd
commit 9d415e4ec6
2 changed files with 71 additions and 18 deletions

View File

@@ -1,6 +1,7 @@
import inspect
import logging
import os
import sys
from collections import Counter
from pathlib import Path
@@ -8,7 +9,7 @@ from time import gmtime, strftime
import pytest
from sanic import text
from sanic import Sanic, text
from sanic.exceptions import FileNotFound
@@ -21,6 +22,22 @@ def static_file_directory():
return static_directory
@pytest.fixture(scope="module")
def double_dotted_directory_file(static_file_directory: str):
"""Generate double dotted directory and its files"""
if sys.platform == "win32":
raise Exception("Windows doesn't support double dotted directories")
file_path = Path(static_file_directory) / "dotted.." / "dot.txt"
double_dotted_dir = file_path.parent
Path.mkdir(double_dotted_dir, exist_ok=True)
with open(file_path, "w") as f:
f.write("DOT\n")
yield file_path
Path.unlink(file_path)
Path.rmdir(double_dotted_dir)
def get_file_path(static_file_directory, file_name):
return os.path.join(static_file_directory, file_name)
@@ -578,3 +595,40 @@ def test_resource_type_dir(app, static_file_directory):
def test_resource_type_unknown(app, static_file_directory, caplog):
with pytest.raises(ValueError):
app.static("/static", static_file_directory, resource_type="unknown")
@pytest.mark.skipif(
sys.platform == "win32",
reason="Windows does not support double dotted directories",
)
def test_dotted_dir_ok(
app: Sanic, static_file_directory: str, double_dotted_directory_file: Path
):
app.static("/foo", static_file_directory)
double_dotted_directory_file = str(double_dotted_directory_file).lstrip(
static_file_directory
)
_, response = app.test_client.get("/foo/" + double_dotted_directory_file)
assert response.status == 200
assert response.body == b"DOT\n"
def test_breakout(app: Sanic, static_file_directory: str):
app.static("/foo", static_file_directory)
_, response = app.test_client.get("/foo/..%2Fstatic/test.file")
assert response.status == 400
@pytest.mark.skipif(
sys.platform != "win32", reason="Block backslash on Windows only"
)
def test_double_backslash_prohibited_on_win32(
app: Sanic, static_file_directory: str
):
app.static("/foo", static_file_directory)
_, response = app.test_client.get("/foo/static/..\\static/test.file")
assert response.status == 400
_, response = app.test_client.get("/foo/static\\../static/test.file")
assert response.status == 400