签入版本
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
"""utils/ip.py 可信代理白名单:仅直连对端命中白名单才信任 X-Forwarded-For。"""
|
||||
import types
|
||||
|
||||
from utils import ip as ip_mod
|
||||
from utils.ip import get_client_ip
|
||||
|
||||
|
||||
def _make_request(client_host, xff=None):
|
||||
req = types.SimpleNamespace()
|
||||
req.client = types.SimpleNamespace(host=client_host)
|
||||
req.headers = {'X-Forwarded-For': xff} if xff else {}
|
||||
return req
|
||||
|
||||
|
||||
def test_proxy_count_zero_ignores_xff(monkeypatch):
|
||||
# TRUSTED_PROXY_COUNT=0:即使带 XFF 头也不信任,直接返回 TCP 层 IP
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_COUNT', 0)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_IPS', frozenset({'127.0.0.1'}))
|
||||
assert get_client_ip(_make_request('203.0.113.9', xff='1.2.3.4')) == '203.0.113.9'
|
||||
|
||||
|
||||
def test_proxy_count_positive_but_no_whitelist_is_fail_closed(monkeypatch):
|
||||
# 配了 TRUSTED_PROXY_COUNT 但未配 TRUSTED_PROXY_IPS → 不信任 XFF(fail-closed)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_COUNT', 1)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_IPS', frozenset())
|
||||
assert get_client_ip(_make_request('203.0.113.9', xff='1.2.3.4')) == '203.0.113.9'
|
||||
|
||||
|
||||
def test_peer_not_in_whitelist_rejects_xff(monkeypatch):
|
||||
# 直连对端不是可信代理(应用被直接暴露,如 Docker bridge 映射端口)
|
||||
# → 客户端伪造的 XFF 被忽略,返回真实对端 IP
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_COUNT', 1)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_IPS', frozenset({'10.0.0.1'}))
|
||||
assert get_client_ip(_make_request('203.0.113.9', xff='1.2.3.4')) == '203.0.113.9'
|
||||
|
||||
|
||||
def test_peer_in_whitelist_trusts_xff(monkeypatch):
|
||||
# 单层代理:XFF 仅含客户端 IP(由可信代理追加),跳过最右侧 1 个代理条目即客户端
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_COUNT', 1)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_IPS', frozenset({'10.0.0.1'}))
|
||||
assert get_client_ip(_make_request('10.0.0.1', xff='1.2.3.4')) == '1.2.3.4'
|
||||
|
||||
|
||||
def test_peer_in_whitelist_spoofed_left_entry_ignored(monkeypatch):
|
||||
# 客户端伪造条目只会出现在 XFF 左侧(由可信代理追加的在其右侧),伪造 IP 被忽略
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_COUNT', 1)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_IPS', frozenset({'10.0.0.1'}))
|
||||
assert get_client_ip(_make_request('10.0.0.1', xff='6.6.6.6, 1.2.3.4')) == '1.2.3.4'
|
||||
|
||||
|
||||
def test_peer_in_whitelist_fewer_entries_than_proxies(monkeypatch):
|
||||
# 代理条目少于层数(部分代理未追加 XFF)→ 回退到最右侧条目,避免拿到代理 IP
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_COUNT', 2)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_IPS', frozenset({'10.0.0.2'}))
|
||||
assert get_client_ip(_make_request('10.0.0.2', xff='1.2.3.4')) == '1.2.3.4'
|
||||
|
||||
|
||||
def test_peer_in_whitelist_multiple_proxy_layers(monkeypatch):
|
||||
# 两层代理:XFF=[客户端, 外层代理],最内层可信代理是直连对端(不在 XFF 内),
|
||||
# 跳过最右侧 2 个代理条目取真实客户端
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_COUNT', 2)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_IPS', frozenset({'10.0.0.2'}))
|
||||
assert get_client_ip(_make_request('10.0.0.2', xff='1.2.3.4, 10.0.0.1')) == '1.2.3.4'
|
||||
|
||||
|
||||
def test_no_client_falls_back_to_localhost(monkeypatch):
|
||||
req = types.SimpleNamespace(client=None, headers={})
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_COUNT', 1)
|
||||
monkeypatch.setattr(ip_mod, 'TRUSTED_PROXY_IPS', frozenset({'10.0.0.1'}))
|
||||
assert get_client_ip(req) == '127.0.0.1'
|
||||
Reference in New Issue
Block a user