Skip to content

Commit f2b8232

Browse files
committed
修复:审计未保持 WebSocket 的 101 升级
1 parent e83169b commit f2b8232

3 files changed

Lines changed: 31 additions & 9 deletions

File tree

‎packages/eval/harbor/egress_filter.py‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,11 @@ def response(flow: object) -> None:
154154
response = getattr(flow, "response", None)
155155
if getattr(response, "status_code", None) != 101:
156156
return
157-
headers = getattr(response, "headers", None)
158-
upgrade = ""
159-
if headers is not None:
160-
try:
161-
upgrade = str(headers.get("upgrade", "") or "")
162-
except Exception:
163-
upgrade = ""
164-
if upgrade.lower() == "websocket":
157+
# mitmproxy 12.2.3 sets flow.websocket before HttpResponseHook only when
158+
# the 101 is a real WebSocket upgrade (Upgrade + version 13 + option on).
159+
# A websocket Upgrade header alone still falls through to CloseConnection
160+
# under rawtcp=false and must be audited.
161+
if getattr(flow, "websocket", None) is not None:
165162
return
166163
record_raw_tunnel(flow)
167164

‎packages/eval/harbor/test_egress_filter.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,12 +308,30 @@ def test_response_audits_a_non_websocket_101_upgrade(self) -> None:
308308
"response": SimpleNamespace(
309309
status_code=101, headers={"upgrade": "websocket"}
310310
),
311+
"websocket": object(),
311312
"server_conn": SimpleNamespace(address=("origin", 19082)),
312313
},
313314
)()
314315
MODULE.response(websocket)
315316
self.assertEqual(len(MODULE.AUDIT_PATH.read_text().splitlines()), 1)
316317

318+
invalid = type(
319+
"Flow",
320+
(),
321+
{
322+
"response": SimpleNamespace(
323+
status_code=101, headers={"upgrade": "websocket"}
324+
),
325+
"server_conn": SimpleNamespace(address=("origin", 19082)),
326+
},
327+
)()
328+
MODULE.response(invalid)
329+
self.assertEqual(len(MODULE.AUDIT_PATH.read_text().splitlines()), 2)
330+
self.assertEqual(
331+
json.loads(MODULE.AUDIT_PATH.read_text().splitlines()[1])["ruleId"],
332+
"raw_tunnel",
333+
)
334+
317335
def test_next_layer_replaces_raw_tcp_with_a_closer(self) -> None:
318336
class FakeTCPLayer:
319337
def __init__(self, context: object) -> None:

‎packages/eval/harbor/test_egress_filter_live.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,14 @@ def connect_via_proxy(cls, host: str, port: int, payload: bytes = b"CLIENT\n") -
323323
@classmethod
324324
def audit_records(cls) -> list[dict[str, object]]:
325325
listed = subprocess.run(
326-
["docker", "exec", cls.proxy, "cat", "/opt/maka-egress-state/hits.jsonl"],
326+
[
327+
"docker",
328+
"exec",
329+
cls.proxy,
330+
"sh",
331+
"-c",
332+
"if [ -f /opt/maka-egress-state/hits.jsonl ]; then cat /opt/maka-egress-state/hits.jsonl; fi",
333+
],
327334
capture_output=True,
328335
text=True,
329336
timeout=COMMAND_TIMEOUT_S,

0 commit comments

Comments
 (0)