Skip to content

Commit 558f950

Browse files
authored
fix(security): add localhost rule to default_proxy_filter (#50)
* fix(security): add `localhost` rule to `default_proxy_filter` * docs(CHANGELOG): update `CHANGELOG.md`
1 parent 1807434 commit 558f950

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3636
- [#46](https://github.com/WSH032/fastapi-proxy-lib/pull/46) - fix: don't use module-level logging methods. Thanks [@dvarrazzo](https://github.com/dvarrazzo)
3737
- [#49](https://github.com/WSH032/fastapi-proxy-lib/pull/49) - fix!: bump `httpx-ws >= 0.7.1` to fix frankie567/httpx-ws#29. Thanks [@WSH032](https://github.com/WSH032)!
3838

39+
### Security
40+
41+
- [#50](https://github.com/WSH032/fastapi-proxy-lib/pull/50) - fix(security): add `localhost` rule to `default_proxy_filter`. Thanks [@WSH032](https://github.com/WSH032)!
42+
3943
### Removed
4044

4145
- [#49](https://github.com/WSH032/fastapi-proxy-lib/pull/49) - Drop support for `Python 3.8`.

src/fastapi_proxy_lib/core/_tool.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,12 @@ def check_http_version(
370370
def default_proxy_filter(url: httpx.URL) -> Union[None, str]:
371371
"""Filter by host.
372372
373-
If the host of url is ip address, which is not global ip address, then will reject it.
373+
Reject the following hosts:
374+
375+
- if the host is ip address, and is not global ip address. e.g:
376+
- `http://127.0.0.1`
377+
- `http://192.168.0.1`
378+
- if the host contains "localhost".
374379
375380
Warning:
376381
It will consumption time: 3.22~4.7 µs ± 42.6 ns.
@@ -383,8 +388,12 @@ def default_proxy_filter(url: httpx.URL) -> Union[None, str]:
383388
str: should rejetc the proxy request.
384389
The `str` is the reason of reject.
385390
"""
391+
host = url.host
392+
if "localhost" in host:
393+
return "Deny proxy for localhost."
394+
386395
try:
387-
ip_address = ipaddress.ip_address(url.host)
396+
ip_address = ipaddress.ip_address(host)
388397
except ValueError:
389398
return None
390399

@@ -403,7 +412,7 @@ def warn_for_none_filter(proxy_filter: None) -> ProxyFilterProto: ...
403412

404413

405414
def warn_for_none_filter(
406-
proxy_filter: Union[ProxyFilterProto, None]
415+
proxy_filter: Union[ProxyFilterProto, None],
407416
) -> ProxyFilterProto:
408417
"""Check whether the argument `proxy_filter` is None.
409418

tests/test_core_lib.py

+27-4
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,33 @@ async def _() -> JSONResponse:
9090

9191
def test_func_default_proxy_filter() -> None:
9292
"""Test `fastapi_proxy_lib.core._tool.default_proxy_filter()`."""
93-
# 禁止访问私有IP
94-
assert default_proxy_filter(httpx.URL("http://www.example.com")) is None
95-
assert default_proxy_filter(httpx.URL("http://1.1.1.1")) is None
96-
assert default_proxy_filter(httpx.URL("http://127.0.0.1")) is not None
93+
# prevent access to private ip
94+
95+
def _check(url: str, should_pass: bool) -> None:
96+
httpx_url = httpx.URL(url)
97+
if should_pass:
98+
assert default_proxy_filter(httpx_url) is None
99+
else:
100+
assert default_proxy_filter(httpx_url) is not None
101+
102+
def should_pass(url: str) -> None:
103+
_check(url, True)
104+
105+
def should_not_pass(url: str) -> None:
106+
_check(url, False)
107+
108+
# passed
109+
should_pass("http://www.example.com")
110+
should_pass("http://www.example.com/path")
111+
should_pass("http://1.1.1.1")
112+
113+
# private ip
114+
should_not_pass("http://127.0.0.1")
115+
should_not_pass("http://[::1]")
116+
should_not_pass("http://192.168.0.1")
117+
should_not_pass("http://10.0.0.1")
118+
should_not_pass("http://172.31.0.1")
119+
should_not_pass("http://localhost")
97120

98121

99122
def test_non_filter_warning_for_forward_proxy() -> None:

0 commit comments

Comments
 (0)