ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenMed 浏览器网络出口证明:用 network_egress_check 验证 local-first 去标识化会话零外发

OpenMed 浏览器网络出口证明:用 network_egress_check 验证 local-first 去标识化会话零外发 OpenMed 浏览器网络出口证明用 network_egress_check 验证 local-first 去标识化会话零外发【免费下载链接】openmedLocal-first healthcare AI: clinical NER HIPAA PII de-identification that runs 100% on-device. 2,200 medical models, 21 languages, Apple MLX Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmedOpenMed 的浏览器端 Demo 是严格 local-first 的页面不发起任何初始网络请求、不内置模型权重、没有云端回退模型资产由用户显式提供并在本机加载。但UI 断言显示处理成功并不能证明数据没有离开浏览器。docs/demo/browser-egress.md记录的 scripts/web/network_egress_check.py 正是为此设计的一个轻量、零依赖的请求探针它观察一次合成去标识化会话中浏览器发出的全部请求事件凡是不在显式模型资产白名单内的 HTTP(S) 请求一律判定为违规。读完本文你将掌握如何用该探针在 Playwright 浏览器测试和离线单元测试中捕获请求、配置最严格的模型资产白名单、理解其隐私安全的报告格式并用 CLI 对已保存的请求 trace 做可复现的出口审计。为什么 UI 断言不足以证明零出口浏览器 Demo 的 local-first 属性体现在多个层面见 docs/demo/web/README.md初始加载只使用仓库自有的同源 HTML/CSS/字体/JavaScript运行时与模型路径必须解析到页面自身 originCSP 将脚本、Worker 与连接限制在同源外加本地blob:Worker笔记与问题输入不做任何持久化。然而页面渲染出了正确的脱敏结果只能说明推理在本地完成无法排除测试期间页面曾向某个 API、分析端点或 CDN 发送过请求——尤其是当请求失败或结果被悄悄忽略时UI 断言根本无法感知。因此出口证明需要的是对请求事件的独立观测记录会话期间每一个发出的请求再与一个明确声明过的策略比对。这正是 scripts/web/network_egress_check.py 扮演的角色——它是一段可执行的隐私声明把本会话未发生未预期的网络外发从口头承诺变成可断言的测试结果。探针设计无传输、只观察事件探针的首要设计原则是彻底无传输transport-free。模块文档明确写道它从不打开 socket、不解析主机、不下载资源、不检查请求头与请求体。在 tests/browser/test_network_egress.py 的回归测试中socket.socket被 monkeypatch 成直接抛错验证了探针在任何情况下都不会发起真实网络操作——整个检查过程只消费调用方浏览器测试或 JSON trace供给的请求事件对象。请求被分类时遵循严格的 fail-closed 语义分类集合_CLASSIFICATIONS只有四类见 network_egress_check.py分类含义是否算违规browser-internaldata:、blob:、about:资源视为浏览器内部机制否model-assetURL 命中显式配置的模型资产白名单且方法为GET否invalid-urlURL 无法被规范解析如超长、含不可打印字符或仅 HTTP(S)/空 scheme 但解析失败是unexpected-network其他一切网络形态请求API、CDN、WebSocket、file:、非 GET 等是data:、blob:、about:被硬编码在NON_NETWORK_SCHEMESnetwork_egress_check.py中视为浏览器内部资源不需要任何网络白名单即可通过file:请求失败关闭——因为远程文件共享可以跨越机器边界file://remote-share/...虽非 HTTP仍归类为unexpected-network测试见 tests/browser/test_network_egress.py网络 scheme 白名单NETWORK_SCHEMES覆盖ftp/http/https/ws/wssnetwork_egress_check.py即不只盯 HTTP 抓包WebSocket/EventSource 等连接形式同样会被拦截。在浏览器测试中捕获一次动作capture_browser_requests探针的核心 API 是capture_browser_requests上下文管理器它接受 Playwright 风格的 page 对象但不导入 Playwright因此浏览器依赖保持可选。下面是文档中的完整用法MODEL_ASSETS为本地模型服务前缀from scripts.web.network_egress_check import capture_browser_requests MODEL_ASSETS http://127.0.0.1:8000/models/synthetic-redactor/ with capture_browser_requests( page, allowed_model_assets(MODEL_ASSETS,), ) as egress: page.get_by_role(button, nameRedact synthetic note).click() egress.assert_clean()capture_browser_requests的实现network_egress_check.py非常直白构造一个NetworkEgressProbe并attach(page)即向 page 注册on(request, ...)监听退出with块时detach()移除监听。NetworkEgressProbe同时兼容 Playwright 风格的事件订阅 APIon/remove_listener/off并可反复attach/detach测试见 tests/browser/test_network_egress.py。若探针重复 attach 到两个 page会抛出RuntimeError(network egress probe is already attached)。使用时机与白名单配置要点在证明应用动作时挂载即页面与样式表已完成设置、即将执行目标操作如点击脱敏按钮之前 attach确保记录的是动作触发的全部请求。若动作会加载本地模型把预期请求收敛到最窄的目录前缀或精确资产 URL。allowed_model_assets可传入单个字符串或可迭代的字符串集合。禁止 host 级白名单与通配符https://models.example.invalid、https://models.example.invalid/、.../models/*这类条目在构造探针时即抛ValueError测试见 tests/browser/test_network_egress.py。原因是 host 级条目等价于这个域名随便连无法证明没有把数据发给同域下的分析端点。目录前缀的信任边界以/结尾的前缀信任其下所有无查询串的GET路径。若模型 host 需要一个固定缓存查询参数则必须把完整资产 URL含查询写进白名单因为目录前缀不接受查询前缀带查询的条目本身也在构造时被拒绝。GET是硬性要求即便 URL 精确命中白名单非GET方法如POST依然判为unexpected-network——因为非 GET 可能携带上传体仅含 URL 的 trace 条目方法未知同样失败关闭详见下文离线单元测试。对 API、分析端点、CDN、WebSocket 或其他远程数据服务的任何请求egress.assert_clean()都会抛出NetworkEgressViolation继承自AssertionError异常消息只含违规计数不含任何原始 URL。路径重解释防护目录前缀的匹配不是简单的字符串前缀比较。在放行前URL 路径要经过_is_safe_url_pathnetwork_egress_check.py的多轮解码校验任何可能被浏览器、代理或服务端重新解释的路径形态都会被拒绝控制字符ASCII 32 或 127与反斜杠\编码分隔符%2e点、%2f斜杠、%5c反斜杠以及它们的双重编码形式如%252e最多展开 4 轮点段./与../无法严格解码的畸形百分号编码。回归测试覆盖了synthetic-redactor/../submit、%2e%2e/submit、%252e%252e/submit、safe%2f..%2fsubmit、safe\..\submit等 5 种逃逸尝试全部被判定为违规tests/browser/test_network_egress.py。同时前缀匹配只作用于路径层级允许.../synthetic-redactor/config.json但.../synthetic-redactor-copy/model.onnx这种兄弟路径不会误命中tests/browser/test_network_egress.py。离线单元测试assert_no_unexpected_requests同样的逻辑可以在不启动浏览器的情况下用合成的请求事件做纯离线单元测试。文档示例from scripts.web.network_egress_check import assert_no_unexpected_requests assert_no_unexpected_requests( [ { method: GET, resource_type: fetch, url: http://127.0.0.1:8000/models/synthetic-redactor/model.onnx, } ], allowed_model_assets(MODEL_ASSETS,), )assert_no_unexpected_requests是check_network_egress(...).assert_clean()的便捷封装network_egress_check.py而check_network_egress接收任意可迭代的请求对象并逐条送入探针不发起任何网络调用。record方法network_egress_check.py接受的请求对象有三种形态Playwright 请求对象、含url字段的映射dict、或裸 URL 字符串。有几个值得注意的 fail-closed 细节仅 URL 字符串的条目方法未知裸字符串或缺少method的 dict 无法证明该方法就是GET、也无法证明没有上传体因此即使 URL 命中白名单也归类为unexpected-network测试见 tests/browser/test_network_egress.py。callable 属性绝不执行探针读取请求对象的url/method/resource_type属性时若发现值是 callable函数一律视作缺失而不是调用它——防止请求对象通过属性 getter 注入任意代码这类攻击面tests/browser/test_network_egress.py。字符串子类的钩子不会运行URL 与方法在分类前都会经_plain_text做一次 UTF-8 往返拷贝字符串子类上的strip/encode钩子不会被触发tests/browser/test_network_egress.py。属性访问异常安全降级若请求对象属性抛异常事件被归类为安全的invalid-url异常值不会进入任何输出tests/browser/test_network_egress.py。EgressReport只留摘要不落原文探针的产出是EgressReportnetwork_egress_check.py一个完全确定性的报告对象对同一请求序列两次生成的 JSON 完全一致无时间戳、随机 ID 或输入顺序漂移见 tests/browser/test_network_egress.py。其中每个事件对应一条RequestSummary只保留index事件序号method规范化的 HTTP 方法仅限标准方法集合未知值一律归一为UNKNOWNresource_type规范化的资源类型fetch、script、stylesheet、websocket 等受控集合scheme受控集合内的 schemeurl_digest/origin_digest原始 URL 与其 origin 的SHA-256 摘要classification四类分类之一。路径、查询串、fragment、请求头、请求体、浏览器请求对象均不会进入报告或异常文本。每条原始 URL 在请求回调内被即时摘要化随后即被丢弃不驻留在探针内存中测试验证原始 URL 与其中的合成敏感值不会出现在probe.__dict__的 repr 中见 tests/browser/test_network_egress.py。这意味着证明产物可以用于关联重复事件通过摘要却不会把合成笔记文本或原始标识符泄漏到日志与测试输出。安全性不止于不记录还在于不允许注入RequestSummary的__post_init__会对调用方传入的每个字段做严格校验方法必须在标准 HTTP 方法集内、digest 必须恰好 64 位十六进制、classification 必须属于受控集合任何越界值都会抛ValueError(request summary contains invalid safe metadata)且校验失败的值不会出现在异常文本中tests/browser/test_network_egress.py。EgressReport同样要求请求序列是完整、连续索引的不可变 tuple拒绝接收可变列表或乱序数据tests/browser/test_network_egress.py。报告的 JSON 表示带schema_version: 1字段to_json()输出按 key 排序、可稳定 diff。典型输出形如{ allowed_model_asset_count: 1, network_request_count: 1, passed: true, request_count: 1, requests: [ { classification: model-asset, index: 0, method: GET, origin_digest: 3f4c..., resource_type: fetch, scheme: http, url_digest: 9a2b... } ], schema_version: 1, unexpected_request_count: 0 }CLI检查已保存的请求 trace浏览器会话之外探针也提供命令行入口用于审计一个已经落盘的本地 JSON trace。CLI不执行任何网络操作只读取本地文件并输出同样的安全报告.venv/bin/python scripts/web/network_egress_check.py \ /tmp/synthetic-browser-trace.json \ --allow-model-asset http://127.0.0.1:8000/models/synthetic-redactor/ \ --report /tmp/browser-egress-report.json参数说明对应build_parser见 network_egress_check.pytrace位置参数JSON 文件路径。文件内容必须是请求对象的 JSON 列表或带requests列表的对象见_load_trace的校验逻辑network_egress_check.py--allow-model-asset URL_OR_PREFIX可重复指定每个预期的模型 URL 或前缀一次校验规则与 API 完全一致拒绝 host-only、通配符、查询前缀等--report PATH可选的报告写出路径。退出码语义明确0表示未观察到意外请求1表示 trace 中存在意外出口2表示本地 trace 或策略无效例如文件损坏、超尺寸、JSON 结构不对。报告同时会打印到标准输出。CLI 的输入处理同样是隐私安全的trace 文件大小有上限_MAX_TRACE_BYTES8 MiB读取与解析错误被归一化为不含原始路径或异常值的ValueErrortests/browser/test_network_egress.py即使 trace 里带有post_data之类的字段也只会被忽略而不会进入报告tests/browser/test_network_egress.py。固定安全预算越界即失败为了抵御失控或恶意构造的输入探针为所有资源维度设置了固定预算network_egress_check.py任何越界都 fail closed 并抛出源安全的错误预算常量默认值越界行为模型资产白名单条目数_MAX_MODEL_ASSET_PATTERNS256抛ValueError观测事件总数_MAX_REQUESTS10,000抛ValueError本地 trace 文件大小_MAX_TRACE_BYTES8 MiBCLI 退出码 2单个 URL 长度_MAX_URL_LENGTH8,192URL 置空 → 分类为invalid-url事件数上限在测试中被 monkeypatch 缩小后验证第 3 条记录会触发ValueError(request trace exceeds the supported event count)且已记录计数保持不变tests/browser/test_network_egress.py。超长 URL 的测试则确认敏感内容既不会进入报告也不会残留在探针内存中tests/browser/test_network_egress.py。即使请求迭代器中途抛异常异常值也会被吞掉只保留中性的ValueError(request trace could not be read)tests/browser/test_network_egress.py。与浏览器 Demo 的整体配合这套出口证明不是孤立的工具它对应的是 docs/demo/web/Maple WebGPU 临床工作台与 docs/demo/privacy-playground/隐私实验场这类浏览器 Demo 的隐私承诺。Demo 侧的实际防线包括运行时适配器契约要求networkPolicy: same-origin-model-assets-only适配器只允许从modelUrl页面自身 origin 的本地模型包目录获取运行时与模型文件CSP 限制脚本、Worker 与连接全部同源笔记文本只进入内存、绝不进入 URL、请求头、请求体、遥测、异常、控制台或持久化存储详见 docs/demo/web/README.md。在端到端层面浏览器测试同样验证了请求不得携带敏感值tests/browser/privacy-playground.spec.ts 注入一个合成标记值同时发起fetch同源与跨源、sendBeacon、WebSocket、EventSource、XHR共 6 种通道断言页面全部拦截6 blocked且所有被抓取的请求 URL 与请求体中都不包含该标记值。network_egress_check.py的意义正在于把这类行为验证进一步升级为声明式策略证明——不需要依赖某个特定页面实现任何浏览器动作都可以套用同一套白名单语义来断言零外发。边界与正确使用姿势最后文档与源码都明确划定了这个工具的边界使用时务必注意它不是去标识化质量评估器探针只证明没有意外网络请求不评估脱敏结果是否达到 HIPAA Safe Harbor 或其他标准的质量要求它不是合规认证通过assert_clean()不等于通过法规审计也不能替代临床决策保障——输出仍需人工复核它只证明会话内的请求浏览器 DevTools 层面之外的出口如操作系统网络栈、插件不在观测范围内报告保留 SHA-256 摘要是为了关联重复事件若需原文取证应在调用方侧另行设计受控的取证流程白名单要窄不要宽精确 URL 强于目录前缀目录前缀强于任何形式的 host 级条目带查询的资产用完整 URL 白名单目录前缀永远不带查询。将 scripts/web/network_egress_check.py 挂到你的浏览器动作测试与离线 trace 审计中配合 tests/browser/test_network_egress.py 中的回归用例socket 禁用、敏感值不泄漏、路径重解释拒绝、预算失败关闭等 20 余项即可把local-first、零外发从一个口号变成每次回归都自动验证的硬性约束。【免费下载链接】openmedLocal-first healthcare AI: clinical NER HIPAA PII de-identification that runs 100% on-device. 2,200 medical models, 21 languages, Apple MLX Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmed创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表