reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
# WebAPI 环境检测矩阵门禁
本文件用于解决另一类常见失败:Trace 已经列出了 API,补环境也实现了 API,但目标仍因 iframe、Worker、PerformanceTimeline、DOM/CSSOM、枚举、任务队列或 writer 分支行为不像真实浏览器而进入错误分支。Trace API 覆盖矩阵回答“访问了什么”,本矩阵回答“访问到的浏览器行为是否一致”。
本文件只用于授权范围内的网页端 Node.js 补环境、真实浏览器基线采样和 Node 行为 diff。不得把它解释为厂商专用绕过流程;遇到 JSVMP / opcode / 字节码解释器时仍只记录环境行为、请求链和 writer 分支,不主动分析虚拟机源码。
## 触发条件
出现以下任一信号时,在进入真实请求、长跑验证或 final writer 判定前必须建立 WebAPI 环境检测矩阵:
- Trace / 阶段报告中出现 `iframe`、`srcdoc`、`contentWindow`、`contentDocument`、`defaultView`、`document.write`、`document.close`。
- 出现 `Worker`、`SharedWorker`、`DedicatedWorkerGlobalScope`、`postMessage`、`MessageChannel`、`MessagePort`、`terminate`、Worker 内 timer 或 Worker 内 `performance`。
- 出现 `PerformanceObserver`、`PerformanceObserverEntryList.getEntries`、`PerformanceResourceTiming`、`PerformancePaintTiming`、`performance.mark`、`performance.getEntries*`、XHR / image / favicon resource timing。
- 出现 `XMLHttpRequest`、`fetch`、`Request`、`Response`、`Headers`、`navigator.sendBeacon`,且目标路径依赖动态资源、Cookie、challenge、telemetry、resource timing 或 writer 分支。
- 出现 `Object.keys`、`Object.getOwnPropertyNames`、`Reflect.ownKeys`、descriptor、getter / setter、prototype walk、brand check、`Function.prototype.toString` 多通道。
- 出现 `this.__xxx`、`this._xxx`、`__readyState`、`__headers`、`__children`、`Object.defineProperty(obj, "__xxx")`、`defineValue(obj, "_xxx")` 等浏览器对象私有状态泄露迹象。
- 出现 `structuredClone`、`DataCloneError`、`MessagePort.prototype.postMessage(fn)`、Error stack / message 差异。
- 出现 DOM / CSSOM 完整性检查:`DOMParser`、`innerHTML`、Comment/Text 原型、`HTMLUnknownElement`、`textarea`、`option`、`select`、`HTMLCollection`、`ShadowRoot`、`CSSStyleSheet.insertRule`、`CSSRuleList`、`getComputedStyle`、`document.links/images/forms/title/on*`。
- 出现 writer 分支差异,例如同一链路中 Node 停在 continuation / reload writer,而真实浏览器进入 form writer / final writer。
## 必须产物
触发本门禁后,进入真实请求验证前至少生成:
```text
case/fixtures/browser-env-detection-baseline.json
case/tmp/node-env-detection-audit.json
case/notes/webapi-env-detection-matrix.md
```
如果已经有高强度 diff 文件,也要在 `case/notes/high-intensity-env-diff.md` 中引用本矩阵结论。若暂时不能生成真实浏览器 baseline,必须在矩阵中标记为 `needs-browser-baseline` 并说明阻塞原因,不得把 Node probe 通过当作真实浏览器一致。
矩阵状态不能自行证明一致。浏览器 baseline 与 Node audit 的每个触发类别必须包含同名 probe 和实际观测值;`check_webapi_env_detection_matrix.js` 将深度比较观测结果。空类别数组、只有 `status: matched` 或只有证据路径而没有结果均视为未审计。两端必须记录相同 `probeSuiteVersion` 与 `probeSourceHash`,并用 case 内的 `probeSourceFile` 让门禁重算真实 SHA-256,证明运行的是同一份 probe 源码;Node audit 还必须记录 `runtimeSourceHash`、`probeVersion` 和可信 `generatedBy`,源码变化后旧 audit 失效。
`browser-env-detection-baseline.json` 至少记录:
```json
{
"schemaVersion": "webapi-env-detection-baseline/v2",
"baselineId": "fp-example-001",
"capturedBy": "ruyiPage+RuyiTrace",
"browser": "Firefox",
"probeSuiteVersion": "webapi-realm-lifecycle/v2",
"probeSourceFile": "fixtures/webapi-env-probe-suite.js",
"probeSourceHash": "<same-sha256-on-browser-and-node>",
"categories": {
"iframe-realm": [
{
"id": "global-relations",
"capability": "realm-global-relations",
"observation": {"selfIsWindow": true, "parentIsMain": true, "defaultViewIsFrame": true}
}
],
"worker-task": [
{
"id": "immediate-terminate",
"capability": "worker-terminate-immediate",
"observation": {"messagesAfterTerminate": []}
}
],
"message-lifecycle": [
{
"id": "sender-close",
"capability": "message-port-close-sender",
"observation": {"delivered": false}
}
],
"performance-timeline": [{"id": "resource-entry-order", "observation": {"entries": []}}],
"dom-cssom": [{"id": "current-path-involved", "observation": {"involved": false}}],
"dom-crud": [
{
"id": "valid-combinator-selector",
"capability": "dom-selector-validity",
"observation": {"selector": "div > span", "throws": false}
}
],
"event-clone-error": [{"id": "xhr-brand", "observation": {"brand": "[object XMLHttpRequest]"}}],
"xhr-fetch-session-bridge": [{"id": "network-mode", "observation": {"mode": "live-session-bridge"}}],
"object-shape": [{"id": "xhr-prototype-chain", "observation": {"chain": ["XMLHttpRequest", "XMLHttpRequestEventTarget", "EventTarget", "Object"]}}],
"private-state-leakage": [{"id": "xhr-private-own-keys", "observation": {"keys": []}}],
"clock-timer": [{"id": "current-path-involved", "observation": {"involved": false}}],
"writer-branch": [{"id": "final-writer-path", "observation": {"writer": "form-writer"}}]
}
}
```
`node-env-detection-audit.json` 至少记录同一组类别、同一 probe 名称、同一 `capability` 和 Node 实际观测值,并额外包含 `generatedBy`、`probeVersion`、`probeSuiteVersion`、`probeSourceFile`、`probeSourceHash`、`runtimeSourceHash`。`not-involved` 也必须以明确 probe 观测表达,不能使用空数组。
以下字段才算实际观测:`observation`、`observed`、`result`、`value`、`output` 或 `expected`。`evidence`、`notes`、`status`、文件路径和人工结论不属于实际观测。
## 状态枚举
矩阵中每个检测项必须选择一个状态:
| 状态 | 含义 | 是否允许真实请求 |
|---|---|---|
| `matched` | 浏览器 baseline 与 Node audit 一致 | 允许 |
| `accepted-diff` | 差异已评估为不影响当前路径,并有证据 | 允许,但必须写风险 |
| `not-involved` | 当前 Trace / writer 路径未涉及 | 允许 |
| `needs-browser-baseline` | 缺真实浏览器基线 | 不允许 |
| `needs-node-audit` | 缺 Node 同 probe audit | 不允许 |
| `mismatch` | 存在未修复行为差异 | 不允许 |
| `native-capability-gap` | 当前 JS / addon / xbs 均无法可靠表达 | 不允许,进入 native 能力缺口闭环 |
| `unknown` | 未判断 | 不允许 |
Realm identity、对象形状、私有状态、Worker/MessagePort 生命周期、DOM CRUD、当前网络 writer 和请求语义属于 P0/P1 时不得使用 `accepted-diff`。这些差异必须修复、补采真实 baseline,或进入明确的 native capability gap。
## 强制 capability
触发下列类别时,browser 与 Node 两端都必须包含这些 capability;probe 名称可以按项目细化,但 capability id 不得省略:
| 类别 | capability |
|---|---|
| `iframe-realm` | `realm-global-relations`、`realm-ecma-constructor-isolation`、`realm-webapi-constructor-isolation`、`realm-object-isolation`、`realm-document-relations`、`realm-navigation-lifecycle` |
| `worker-task` | `worker-global-surface`、`worker-constructor-isolation`、`worker-object-isolation`、`worker-message-order`、`worker-terminate-immediate`、`worker-terminate-deferred` |
| `message-lifecycle` | `message-order`、`message-port-start`、`message-port-close-sender`、`message-port-close-receiver`、`message-port-transfer` |
| `dom-crud` | `dom-tree-mutation`、`dom-live-collections`、`dom-selector-validity`、`dom-html-parsing`、`dom-document-relations`、`dom-mutation-observer` |
## 必查类别
### iframe / Window realm
检查:
- `iframe.contentWindow` / `contentDocument` / `defaultView` 关系。
- `srcdoc`、sandbox、`document.write()`、`document.close()`、load 事件顺序。
- 主窗口与 iframe Window 的 `eval`、`fetch`、`location`、`navigator` descriptor。
- 主窗口与 iframe 的 `Object/Function/Array/Promise`、`Event/EventTarget`、`URL/Blob`、`Headers/Request/Response/XHR` 构造器 identity 必须不同。
- iframe 的 `self/window/globalThis/frames` 指向自身,`parent/top` 指向正确上层;`document.defaultView/contentWindow/contentDocument/frameElement` 关系必须闭合。
- 允许共享同源 Cookie/Storage 后端和 TLS Session,但 navigator/performance/crypto/storage wrapper/fetch/timer 等公开对象不能直接复用主 Realm 实例。
- `Object.keys`、`Object.getOwnPropertyNames`、`Reflect.ownKeys` 的数量、顺序和过滤策略。
- `document.all`、`currentScript`、`readyState`、`defaultView` 是否按目标浏览器可见。
禁止为了推进链路全量放开 raw ownNames;只能基于浏览器 baseline 做窄范围 A/B,并记录为什么该项可见。
### Worker / Message task queue
检查:
- Worker scope 是否有独立 `performance`、`timeOrigin`、`performance.now()` 序列和 UA / baseline 选择。
- Worker 的 `self/globalThis`、构造器图和实例必须独立;Window-only API 必须缺失,主 Window 也不得错误暴露 WorkerGlobalScope-only API。
- Worker 内 `setTimeout` / `clearTimeout` 是否绑定 Worker 私有状态。
- `Worker.prototype.terminate()` 后 pending timer、延迟 `postMessage` 是否清理。
- 立即 terminate 与延迟 terminate 必须分开检测。
- `WorkerGlobalScope.self.postMessage()` 与 `MessagePort.prototype.postMessage()` 是否后续 task 派发,而不是同步栈内派发。
- `addEventListener` / `removeEventListener` / `dispatchEvent` 是否支持 listener object、capture、once、passive、stopImmediatePropagation。
Promise resolved、Worker 回包出现或 probe 不报错都不能单独视为完成;必须验证同步 / 异步顺序和 terminate 后行为。
### MessagePort / postMessage 生命周期
检查:
- `postMessage` 相对当前同步栈、Promise microtask、queueMicrotask、timer 的顺序。
- `start()` 与设置 `onmessage` 的隐式启动行为。
- sender close、receiver close、双方 close、消息入队后 close。
- transfer 后原端口是否失效、目标端口是否保持 entangled。
- `close()` 是否清除监听、待派发 task 和 peer 关系;不能只在发送时检查“对端是否 closed”。
### Performance timeline / resource timing
检查:
- `performance.getEntries()`、`getEntriesByType()`、`getEntriesByName()` 的排序。
- `PerformanceObserver.observe()` 对 `buffered` 与非 `buffered` 的差异。
- `PerformanceObserverEntryList.getEntries()` 回调内容和触发时机。
- XHR readyState 4 / load / loadend 前后 resource entry 是否可见。
- image、favicon、Turnstile / third-party script、flow、`/d/`、`/peek` 等资源是否进入正确 timeline。
- `PerformanceEntry.toJSON()`、paint、mark、resource entry 序列化是否一致。
禁止无条件 synthetic 初始 callback;禁止用插入顺序替代浏览器 `startTime` 排序,除非目标 baseline 证明如此。
### DOM / CSSOM 短值行为
检查:
- `document.createElement(tag)` 的 tag 到构造器映射,特别是未知 tag、`html`、`textarea`、`option`、`select`、`form`、`input`、`img`、`iframe`。
- `innerHTML` / `DOMParser.parseFromString()` 后 Text、CDATA、Comment、Element 原型与 `[object Xxx]`。
- `appendChild/removeChild/insertBefore/replaceChild/replaceChildren` 的移动、重复插入、DocumentFragment 展开、错误类型和 ownerDocument/isConnected 更新。
- `childNodes`、`children`、`getElementsBy*` 的 live 语义与 `querySelectorAll` 的 static 语义。
- 合法选择器如 `div > span` 不得错误抛出 `SyntaxError`;非法选择器必须按浏览器 baseline 抛错。
- HTML parser 不得丢弃 Comment/Text;`innerHTML`、clone/import/adopt 后 document/parent/sibling 关系必须一致。
- `MutationObserver` 的 record 内容、合并策略和 microtask 时序。
- `HTMLCollection`、`NodeList`、`HTMLOptionsCollection` 是否 native-like,是否实时或快照符合目标路径。
- `attachShadow()`、`ShadowRoot.host/mode`、`shadowRoot` descriptor。
- `CSSStyleSheet.insertRule()`、`CSSStyleRule.selectorText/style`、`CSSRuleList.item()`、`getComputedStyle()` 对目标选择器的最小一致性。
- `document.links/images/forms/title/on*`、`document.cookie` 可见性与 descriptor。
### Error / clone / native shape
检查:
- `structuredClone(fn)`、`MessagePort.prototype.postMessage(fn)` 的错误 name / message / stack。
- `Function.prototype.toString.call(fn)`、`fn + ""`、`String(fn)`、保存旧 FTS 后调用。
- 构造函数直接调用 / `new` 调用错误差异。
- `Object.getOwnPropertyDescriptor`、`__lookupGetter__`、`__lookupSetter__`、`hasOwnProperty`、`propertyIsEnumerable`、`for...in`。
- `Object.prototype.toString.call`、`Symbol.toStringTag`、`instanceof`、prototype walk。
### XHR / fetch session bridge
检查:
- `XMLHttpRequest.send()` / `fetch()` / `navigator.sendBeacon()` 是否为 `offline-fixture` 诊断模式,还是 `live-session-bridge` 真实请求模式。
- 真实请求模式是否通过同一 CycleTLS / impers / curl-cffi-node / curl_cffi / cffi_curl / cyCronet Session 发送。
- Python `curl_cffi` 场景是否由 `final.py` 持有唯一 session,并通过 IPC 服务 Node JS runtime 的 XHR/fetch 请求。
- Cookie jar、`document.cookie`、`Set-Cookie`、`getResponseHeader("set-cookie")`、Response headers、body、readyState / Promise / event 顺序是否与浏览器 baseline 一致。
- XHR / fetch 请求是否产生正确的 PerformanceResourceTiming 可见性。
禁止把 fixture / 默认 200 / mock response 写成真实请求成功;禁止在 XHR/fetch 内部直接调用 Node 宿主 `fetch`、`http`、`https`、`axios` 或 Python 普通 `requests`。
### Object shape
检查:
- `Object.keys`、`Object.getOwnPropertyNames`、`Object.getOwnPropertySymbols`、`Reflect.ownKeys` 的数量、顺序和字段名。
- `Object.getOwnPropertyDescriptor`、`hasOwnProperty`、`propertyIsEnumerable`、`for...in`、`in`、`__lookupGetter__`、`__lookupSetter__`。
- 构造函数、prototype、实例对象、集合对象、iframe realm、Worker realm 的 prototype walk。
- `Object.prototype.toString.call(obj)`、`Symbol.toStringTag`、`constructor.name`、`instanceof`。
如对象形状涉及内部状态,应同时生成 `object-shape-audit.md`、`browser-object-shape-baseline.json` 和 `node-object-shape-audit.json`。
### Private state leakage
检查:
- 浏览器可见对象是否存在自定义 `_` / `__` 自有属性,包括 non-enumerable 属性。
- 是否使用 `this.__state`、`this._headers`、`Object.defineProperty(obj, "__readyState")`、`defineValue(obj, "_store")` 或自定义 Symbol 保存内部状态。
- 内部状态是否迁移到 addon / xbs private API、原生内部槽或模块级 `WeakMap`。
发现 `_` / `__` 私有状态泄露时直接阻断;不能用 `enumerable:false` 作为豁免。
### Clock / timer
检查:
- `Date.now()`、`new Date()`、主线程 `performance.now()`、Worker `performance.now()` 是否来自同一 baseline 策略。
- 虚拟 timer driver 是否只运行到期 timer,不因 sleep cap 把 10s / 30s timer 一轮快进。
- `queueMicrotask`、Promise job、timer task、MessagePort task、PerformanceObserver callback 的相对顺序。
### Writer branch
检查:
- 请求链中每个关键响应对应的 writer 类型:continuation program、reload writer、form writer、final writer。
- Node 与真实浏览器在 final writer 前 300 到 1000 个环境事件的类别差异。
- 是否出现 `HTMLFormElement.submit(true)`、hidden input 创建、`cf_chl_rc_ni` 删除、`Location.reload` 等分支证据。
- 不得把拿到 Cookie、Set-Cookie 或 reload writer 响应写成最终成功;必须记录 writer 类型。
## 阻断规则
- 存在 `mismatch`、`needs-browser-baseline`、`needs-node-audit`、`native-capability-gap` 或 `unknown` 的 P0/P1 检测项时,不得执行真实请求验证、不得宣称 final writer 已闭环。
- 只有类别名称或手工 `matched`、没有逐 probe 浏览器值和 Node 值时,直接阻断。
- browser/Node 的 `probeSuiteVersion`、`probeSourceFile` 或 `probeSourceHash` 缺失,hash 不一致,源文件不在 case 内,或声明 hash 与实际文件不一致,直接阻断。
- iframe/Worker 构造器或公开对象复用主 Realm、MessagePort 只实现单侧 close、DOM probe 把合法 selector 当非法、HTML parser 丢 Comment,直接阻断。
- 存在 `xhr-fetch-session-bridge` 阻断项时,不得宣称 TLS 指纹已解决;fixture/mock 只能作为离线诊断结论。
- 存在 `private-state-leakage` 阻断项时,不得交付;必须迁移到 addon / xbs private API 或 WeakMap。
- 如果后续阶段新增 WebAPI 是因为本矩阵遗漏了已触发检测项,必须标为 `missed-from-webapi-env-matrix` 流程缺陷,并补写矩阵与代码变更记忆。
- 如果真实请求失败但矩阵未覆盖 Worker / performance / iframe / DOM/CSS / writer branch,而 Trace 或阶段报告已经出现这些信号,下一步只能补矩阵和离线 diff,不能继续盲目真实请求。
## 阶段报告记录模板
```markdown
## WebAPI 环境检测矩阵
- 矩阵文件:case/notes/webapi-env-detection-matrix.md
- 浏览器 baseline:case/fixtures/browser-env-detection-baseline.json
- Node audit:case/tmp/node-env-detection-audit.json
- baselineId:
- 触发类别:iframe-realm / worker-task / message-lifecycle / performance-timeline / dom-cssom / dom-crud / event-clone-error / xhr-fetch-session-bridge / object-shape / private-state-leakage / clock-timer / writer-branch
- 阻断项:无 / 列表
- writer 分支:真实浏览器 = form writer;Node = reload writer / continuation / form writer
| 类别 | 检测项 | 浏览器证据 | Node 证据 | 状态 | 处理 |
|---|---|---|---|---|---|
| worker-task | postMessage async task | fixtures/... | tmp/... | matched | 保持 |
```
## 检查命令
```bash
node scripts/check_webapi_env_detection_matrix.js --case-dir case --markdown
node scripts/check_webapi_env_detection_matrix.js --case-dir case --require --require-writer-branch --json
```
检查失败时,下一步只能补浏览器 baseline、Node audit、矩阵、native 能力缺口或离线 diff;不能继续真实请求验证。