# 前端密码能力通用化重构与适配器路线 > 状态:G0–G4 已完成并通过真实浏览器/独立验证器验收;G5 按真实样本继续推进 > > 更新时间:2026-07-21 > > 关联文档:[`AUTO_PROFILE_INFERENCE_ARCHITECTURE.md`](AUTO_PROFILE_INFERENCE_ARCHITECTURE.md)、[`DEEP_CAPTURE_ARCHITECTURE.md`](DEEP_CAPTURE_ARCHITECTURE.md)、[`BROWSER_TRANSFORM_GATEWAY.md`](BROWSER_TRANSFORM_GATEWAY.md)、[`study.md`](study.md) ## 1. 结论 当前实现的**数据模型、请求推断和 G4 高价值协议覆盖是通用的;WASM、流式协议与长尾生态仍需由真实样本继续驱动**。 现有靶场体验顺滑,主要因为它同时满足了三个有利条件: 1. 使用全局可访问的 `window.CryptoJS` 或 `window.JSEncrypt`; 2. 加密后通过常规 Fetch/Form 请求发送; 3. 密码调用输出可以和请求字段建立精确值关联。 生产代码并没有依赖 `127.0.0.1:82`、`/encrypt/aes.php`、`/encrypt/rsa.php`、固定用户名、固定密码或固定业务字段。请求字段推断也已经支持 JSON、Form、Header、Query 和完整 Body。因此当前实现不是为靶场硬编码的结果。 但“没有靶场硬编码”不等于“已经覆盖真实世界”。当前 MAIN-world 录制器通过有界 manifest 为以下可访问对象安装语义 Hook: - 当前页面 Realm 的 `SubtleCrypto`; - `CryptoJS`、`JSEncrypt`、`sm-crypto` 与 `node-forge`; - `jsrsasign` 的 Signature/JWS/JWT/JWK; - 页面显式暴露的 `jose` 高层 builder 与 verify/decrypt 函数。 没有全局导出的 ESM/Webpack 闭包、Worker 内密码运算、WASM 和完全未知的业务封装不会通过侵入 bundler cache 强行发现;它们继续走请求/消息边界、WebCrypto、证据图和 Deep Capture 业务闭包恢复。这是正式的通用路径,不是失败后的临时兜底。 因此本轮重构采用以下产品判断: > 已知库适配器是语义加速器,不是产品能力的地基。请求与消息边界、业务函数恢复、文档绑定 callable 和服务端认可的真实回放,才是通用能力的地基。 最终验收不是“界面显示识别到 AES/RSA”,而是: ```text 用户执行一次真实操作 -> 插件定位明文、页面业务调用和线上目标 -> 已知库时给出准确算法语义,未知库时仍能定位业务封装 -> 页面保留 key / IV / nonce / receiver / closure / WASM 状态 -> Yakit Web Fuzzer 编辑明文 -> 浏览器生成真实线上报文 -> 独立服务端成功解密、验签或接受请求 ``` 算法名称可以暂时未知,业务链路不能因此不可用。 ## 2. 重构目标与非目标 ### 2.1 目标 - 支持全局库、打包闭包、混淆函数、Worker 消息边界和 WASM 外围业务函数; - 已知密码库接入同一 adapter contract,不再把逻辑堆入 MAIN-world 录制器; - 未知库也可以从请求/消息边界进入 Deep Capture,恢复上层业务 callable; - 自动 Profile 以请求为中心,保留 AES + RSA + HMAC + timestamp 等同一业务上下文; - 页面秘密始终留在页面对象、闭包、CryptoKey 或 WASM 内存中,不通过协议导出; - 适配器安装、事件归一化、证据建图、AI 分析和 Profile 执行各自独立; - 使用随机化、跨打包形态的真实服务端夹具证明没有按图索骥; - 在录制开启时保持有界开销,录制停止后完整恢复页面 API 且不存在后台轮询。 ### 2.2 非目标 - 不追求穷举所有 JavaScript 密码库; - 不要求先还原算法、密钥或混淆源码才能使用明文网关; - 不把页面 key、PEM、CryptoKey、闭包变量或 WASM 内存导出到扩展、Yak 或 AI; - 不在页面主线程进行全量源码搜索、全局对象枚举或 AST 扫描; - 不为某个站点、接口路径、字段名或靶场流程维护特殊规则; - 不保留旧 provider 枚举、旧录制协议或旧适配器目录的迁移兼容层。 ## 3. 四层通用架构 ```text L0 业务边界探针 Fetch / XHR / Form / sendBeacon / WebSocket / Worker / MessagePort / Navigation | | 有界输入输出、调用顺序、同步/异步栈、值关联 v L1 通用运行时边界 WebCrypto / random / encoding / WebAssembly 装载 / serializer 边界 | | 原生算法元数据、TypedArray 形态、opaque object v L2 已知语义适配器 CryptoJS / JSEncrypt / sm-crypto / node-forge / jsrsasign / jose / sodium ... | | 参数角色、模式、padding、state model、可复跑能力 v L3 未知业务函数恢复 请求断点 -> 页面业务帧排序 -> closure callable -> 自动 Profile ``` 四层不是按顺序全部执行的流水线。L0 始终提供兜底证据;L1/L2 提供更强语义和更精确的断点;L3 在低层 primitive 不足、库不可见或业务封装复杂时恢复完整现场。 ### 3.1 L0:业务边界是最低保证 请求和消息边界回答三个最重要的问题: 1. 哪段值真正离开了页面; 2. 它被写入 Body、字段、Header、Query、WebSocket frame 还是 Worker 消息; 3. 哪个页面调用链在边界之前构造了它。 现有 Fetch/XHR/Form/WebSocket 继续保留,并补齐: - `navigator.sendBeacon`; - `Worker.prototype.postMessage`; - `MessagePort.prototype.postMessage`; - `SharedWorker.port` 消息边界; - 有界同步栈和可用时的异步栈来源; - TypedArray、ArrayBuffer、Blob、FormData 和 transferable 的结构化摘要; - 同一 Trace 内从输入、消息到请求的精确/归一化值关联。 页面侧边界看不到 Worker 内部每一步是事实,不应伪装成已识别。即使 Worker 内部无法安装密码适配器,插件仍可关联“页面明文消息 -> Worker 返回值 -> 请求字段”,并以消息边界或调用 Worker 的页面业务函数作为 callable 捕获入口。 Service Worker 内部运算不属于普通页面 MAIN world。第一阶段只保证通过 `webRequest` 和页面消息/请求边界观察真实线上结果;更深的 Worker/Service Worker 调试目标支持需要独立评估 CDP Target 生命周期,不能和页面适配器混为一个实现。 ### 3.2 L1:通用运行时边界 首批运行时探针包括: - WebCrypto `SubtleCrypto`; - `crypto.getRandomValues` 和 `randomUUID` 的调用关系摘要,不记录随机原值; - `TextEncoder` / `TextDecoder`、Base64、Hex 等有界编码链; - `WebAssembly.instantiate` / `instantiateStreaming` 的模块与实例身份摘要; - 请求边界处的 JSON、Form、Query 和 Header 结构化解析。 不得全局 Hook 每一次 `JSON.stringify`、`encodeURIComponent` 或遍历所有 WASM exports。高频通用函数只在请求边界归一化,或在已确定的 Trace/Deep Capture 窗口内按需观察,避免让正常页面承担持续成本。 WASM 的第一目标不是反编译算法,而是保留调用它的页面业务 wrapper、输入输出关联和实例生命周期。只要该 wrapper 能在原页面复跑,明文网关就不需要导出 WASM 内存或重写算法。 ### 3.3 L2:已知语义适配器 适配器负责把“某个函数被调用”解释成统一语义: - provider/adapter 身份; - symmetric、asymmetric、digest、MAC、signature、KDF 或 key-management family; - data、key、iv、nonce、aad、signature、options 等参数角色; - algorithm、mode、padding、input/output encoding; - stateless、receiver-bound、stateful-session、streaming 或 async-ready 状态模型; - 是否可以安全保留原函数、receiver 和参数模板作为 recorded-call callable。 适配器不负责请求字段推断、UI 文案、AI prompt、Profile 编译或 Bridge RPC。新增库不应修改这些下游层。 ### 3.4 L3:未知业务函数恢复 “不知道是哪一个库”不能成为终点。通用回退流程是: ```text 请求/消息边界已定位 -> 武装下一次相同边界 -> 用户重复一次真实操作 -> 立即发布有界调用栈 -> 排除 extension hook 和已知依赖 frame -> 结合参数相关性、请求接近度、源码位置、同步/异步父栈给业务 frame 排序 -> 捕获完整业务 closure callable -> 页面恢复 -> 用短时样本做页面内回放 ``` 页面函数叫 `encryptPayload`、`pack`、`request` 或 `_0x3f2a` 都不影响流程。AI 可以解释 frame 和参数语义,但只能返回引用既有 evidence 的候选补丁,不能生成并直接执行任意代码。 ## 4. 适配器协议重构 ### 4.1 删除封闭 provider 枚举 当前 `BrowserCryptoProvider` 是 `webcrypto | cryptojs | jsencrypt | forge | custom` 的封闭联合。继续添加库会迫使协议、归一化器、UI 和测试重复修改。 新协议使用有界 adapter ID 和稳定 provider kind: ```ts type BrowserCryptoProviderKind = | "native" | "library" | "business" | "wasm" | "unknown" interface BrowserRecordingCrypto { adapterId: string // 受限 slug,例如 "webcrypto"、"sm-crypto" providerKind: BrowserCryptoProviderKind family: BrowserCryptoFamily operation: string // 适配器内部稳定 operation ID algorithm?: string mode?: string padding?: string inputEncoding?: BrowserPageCallableValueEncoding outputEncoding?: BrowserPageCallableValueEncoding state?: { model: "stateless" | "receiver" | "session" | "stream" | "async-ready" correlationId?: string phase?: "create" | "init" | "update" | "final" | "one-shot" } key?: { kind: "public" | "private" | "secret" | "unknown" bits?: number fingerprint?: string } } ``` `adapterId`、`operation` 和所有字符串必须限长并按字符集校验。UI 显示名来自扩展自带的 adapter manifest,不信任页面提供的 HTML 或展示文本。未知 ID 使用安全的纯文本回退标签。 Deep Capture 不再依赖 `CryptoJS.AES.encrypt` 这类展示字符串查找函数,而是绑定录制器已经保留的 wrapper handle: ```text adapterId + operation + wrapperHandleId + documentId ``` 这样库被混淆、别名导出或方法名重复时,也不会武装错误函数。 ### 4.2 统一 adapter contract ```ts interface PageCryptoAdapter { manifest: { id: string displayName: string providerKind: BrowserCryptoProviderKind dynamic: boolean } discover(context: AdapterDiscoveryContext): AdapterTarget[] install(target: AdapterTarget, host: AdapterHost): AdapterInstallation } interface AdapterInstallation { id: string operations: InstalledOperation[] restore(): void } interface AdapterHost { wrap(input: WrapOperationInput): InstalledOperation emit(input: NormalizedCryptoCall): void retain(input: RetainedCallInput): string | undefined fingerprint(value: unknown): ValueEvidence[] } ``` 公共 `wrap` 基础设施必须统一处理: - 原 property descriptor、原函数和原 receiver; - 同步返回、Promise resolve/reject 和库返回 `false/null` 的语义; - re-entrancy 防护,避免适配器调用辅助方法时递归记录; - 参数与输出大小预算; - wrapper handle 与 Deep Capture 一次性断点; - 页面后续替换函数时不覆盖页面的新值; - restore 只恢复自己仍然拥有的 descriptor; - 停止、清空、导航、grant 撤销和异常安装时的幂等清理。 适配器只能使用 host 提供的 evidence、emit 和 retain 能力,不各自维护事件队列、Trace、指纹算法或 callable registry。 ### 4.3 状态型与流式 API 不能把所有库都按 `encrypt(data, key) -> ciphertext` 的一次函数处理。 例如 node-forge 常见调用链是: ```text createCipher -> start -> update -> finish -> output ``` jsrsasign 的签名流程可能是: ```text new Signature -> init -> updateString/updateHex -> sign ``` 这些调用需要同一 `correlationId` 和 phase 序列。只有满足以下条件才允许生成 recorded-call callable: - 可替换明文输入明确; - 原 receiver/session 仍有效; - 重放不会复用已经消费的流状态; - 输出与请求目标存在 proven link; - 调用没有网络、DOM、导航等额外副作用。 不满足时适配器只提供语义证据,并把候选标记为 `capture-required`,由 Deep Capture 保留上层一次性业务封装。 ### 4.4 晚加载与打包形态 现有每秒扫描动态全局库的方式需要替换为有界调度: - 录制开始时立即检查一次已知全局路径; - 捕获动态 `