Files
MailUI4Agents/client/electron/test
JianFeeeee b4610f1539 fix(安全)★: index.html 加 CSP —— 渲染层的最后一道防线(实测过不误伤)
**为什么现在没有 XSS**:全库 `dangerouslySetInnerHTML` / `innerHTML` /
`insertAdjacentHTML` 命中 **0**,`react-markdown` 无 `rehype-raw`,
`test/markdown-xss.test.mjs` 钉着。⇒ 这条 CSP **不是**为了堵今天的洞,
而是防「有人加一行 `dangerouslySetInnerHTML` 之后那道防线消失」。
★ 而 `sandbox: true` + `contextIsolation: true` **替不了这一层**:
  那两条只挡 node 与跨上下文,**不挡渲染层注入**。

## ★★ 不是照抄模板 —— 每一档都按仓库真实用法定的

· `script-src` **必须**含 `'unsafe-inline'`:上方那段首帧防闪屏脚本要求
  **同步**执行(早于任何外链,见 index.html 头部注释),无法外链化。
  ⇒ 因此 CSP **挡不住注入型 XSS**,只挡 `javascript:` URL / 外部脚本 / `eval`
  (`script-src` 不含 `'unsafe-eval'`)。★ 这一点已写进 meta 上方的注释 ——
  否则下一个人会以为这是严格 CSP。要去掉就得外链化那段脚本,而那会**引入闪屏**。
· `style-src` 同理 + `img-src`/`font-src` 含 `data:`:
  `backgroundStore.ts:252-262` 用 `root.style.setProperty('--bg-image', url("data:image/…"))`
  ⇒ 背景图就是 data URL。
· `connect-src` **只能是 `'self'` + 宽松一档**:网关地址**用户可填**
  (`AccountList` 的 placeholder 就是「Gateway 地址,如 http://192.168.2.60:8180」),
  可以是**任意 host:port** ⇒ 这里没法写成 allow-list。
  真正的防线在渲染层与主进程(导航拦截),不在这一行。
· `object-src 'none'` / `base-uri 'self'` / `frame-ancestors 'none'` / `form-action 'self'`
  是纯收紧,**零兼容代价**。

## ★ 真的用 chromium 实测过它不误伤(不是推理)

无头加载一份带同款 CSP 的页面,结果写进 DOM:
```
id="R"> pending | inline-ran | cssom-ran | eval-BLOCKED
```
⇒ 内联脚本跑(防闪屏有效)、CSSOM 设 data: 背景有效、`eval` 被拦。
且构建产物 `dist/index.html` 里 CSP 确实在位(`npm run build` 后 grep 得到)。

## 判据(markdown-xss 9 → 19,已接线)

新增 10 格。变异测试 5 个全部抓住:删整条 CSP / 去掉 `object-src 'none'` /
去掉 `frame-ancestors` / 去掉 `img-src` 的 `data:` / 加 `'unsafe-eval'`。
★ 顺带把「防闪屏脚本必须是单引号 `classList.add('dark')`」也钉在这里 ——
  `index.html` 的注释声称 `test/theme.test.mjs` 在逐字符断言它,
  **实测 theme.test.mjs 并不断言引号**(它只切 `.dark {}` 色块)⇒ 那条注释是**过期的**,
  历史上被 prettier 改写过一次的事件其实**没有判据在挡**。现已由本条补上。

★ 取 CSP 值时踩了两个坑(都记在判据注释里):`[^>]*` 会在策略里的
  `'self'>` 处提前结束;按行匹配会因 `<meta>` 跨行而只取到第一行。
  ⇒ 判据不匹配标签,只确认 meta 存在再单独取 `content="…"`。

## 边界 / 未做

· CSP 只覆盖**浏览器/Web 侧**;Electron 的 `file://` 加载下 meta CSP 仍生效,
  但主进程那道防线是 `will-navigate` / `setWindowOpenHandler`
  (`test/main-process-security.test.mjs` 钉着)。
· **没在真机上验过 CSP** —— Electron `loadFile()` 那条路未实测
  (只验了 chromium 下的 `file://`)。下次装机时顺手看一眼首帧有没有闪。
2026-10-03 21:21:55 +08:00
..