feat(server): URL清洗三轨制+共享测试向量(D08)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-18 10:15:42 +08:00
parent 73af568c3f
commit 5881046a2d
4 changed files with 63 additions and 9 deletions
+19
View File
@@ -0,0 +1,19 @@
{
"rule_version": "v2",
"vectors": [
{"in": "/product?id=456", "out": "/product?id=456"},
{"in": "/product?id=456&email=a@b.com", "out": "/product?id=456"},
{"in": "/page?phone=13800138000", "out": "/page"},
{"in": "/lp?utm_source=meta&utm_campaign=x", "out": "/lp?utm_source=meta&utm_campaign=x"},
{"in": "/lp?gclid=EAIaIQ&fbclid=IwAR2x", "out": "/lp?gclid=EAIaIQ&fbclid=IwAR2x"},
{"in": "/p?token=abcdef0123456789abcdef0123456789x", "out": "/p"},
{"in": "/p?ref=abcdefghijklmnopqrstuvwxyz012345", "out": "/p"},
{"in": "/p?slug=abcdefghijklmnopqrstuvwxyz0123456", "out": "/p"},
{"in": "/p?cat=sedans&sort=price", "out": "/p?cat=sedans&sort=price"},
{"in": "/p?q=%E5%BC%A0%E4%B8%89%E7%9A%84%E9%82%AE%E7%AE%B1a%40b.com", "out": "/p"},
{"in": "/a/b?name=zhangsan", "out": "/a/b"},
{"in": "/view?v=abc123DEF-_456", "out": "/view?v=abc123DEF-_456"},
{"in": "/long?v=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "out": "/long"},
{"in": "https://user:pass@example.com/p?x=1&email=c@d.com#frag", "out": "https://example.com/p?x=1"}
]
}
+17 -4
View File
@@ -1,7 +1,12 @@
import json
import pathlib
from datetime import datetime, timedelta
from django.utils import timezone
from tracker import constants as C
from tracker.services.validation import validate_event, sanitize_url
VECTORS = json.loads((pathlib.Path(__file__).parent / "fixtures" / "sanitize_vectors.json").read_text(encoding="utf-8"))
NOW = timezone.now()
def _ev(**kw):
@@ -46,11 +51,12 @@ def test_pageview_referrer_url_sanitized():
def test_pageview_referrer_truncated_after_reencode():
"""清洗重编码(中文 → %XX 九倍膨胀)可能超出原长:出门统一截 MAX_STR_LEN=500。"""
ev = _ev(properties={"referrer": "https://www.bing.com/search?q=" + "词" * 200})
assert validate_event(ev) is None # 原文 227 字符过长度门
"""清洗重编码(中文 → %XX 九倍膨胀)可能超出原长:出门统一截 MAX_STR_LEN=500。
用 utm 值驱动:utm 参数三轨制下无条件保留(不走值判别),膨胀路径仍可达。"""
ev = _ev(properties={"referrer": "https://www.bing.com/search?utm_term=" + "词" * 200})
assert validate_event(ev) is None # 原文 237 字符过长度门
ref = ev["properties"]["referrer"]
assert len(ref) == 500 and ref.startswith("https://www.bing.com/search?q=%E8%AF%8D")
assert len(ref) == 500 and ref.startswith("https://www.bing.com/search?utm_term=%E8%AF%8D")
def test_nested_sensitive_key_rejected():
assert validate_event(_ev(properties={"utm": {"utm_a": 1, "user_password": "x"}})) == "sensitive_field" # utm 在白名单内,嵌套敏感键仍须命中
@@ -83,3 +89,10 @@ def test_non_str_path_rejected():
def test_prop_depth_exceeded():
assert validate_event(_ev(properties={"utm": {"a": {"b": 1}}})) == "properties_depth"
def test_sanitize_url_vectors():
for v in VECTORS["vectors"]:
assert sanitize_url(v["in"]) == v["out"], v["in"]
def test_sanitize_rule_version_exported():
assert C.SANITIZE_RULE_VERSION == VECTORS["rule_version"]