# 密封表单字段让页面不再读取明文

> 一项 WICG 提案让浏览器为表单目的地加密敏感值，并公开原型边界、失败方式与仍待标准审查的问题。

「密封表单字段」提案让浏览器用表单目的地发布的公钥加密输入值，页面只拿到加密信封。提案于 2026 年 9 月 21 日进入 WICG proposals 仓库，还包含配套的 `sealed-fields` Content Security Policy 指令，用 `autocomplete` token 指定普通输入框。它已有原型和审查请求，尚未成为浏览器交付的标准功能
（[WICG 提案 issue](https://github.com/WICG/proposals/issues/307)）。

<span id="提案定义的边界"></span>

## 加密与表单集成

explainer 从一个收窄的机密性问题出发。TLS 保护传输中的数据，但普通输入值在提交前仍可被页面
脚本读取。拟议控件会把值加密给表单 `action` 所确定的接收方。其目标是让嵌入页面、页面依赖和
私钥持有者之前的中间设施只接触加密信封。它明确不替代 TLS、不认证用户，也不防御已经失陷的
接收方（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

提案选择新增元素，排除了新增 `input` 类型的方案。explainer 指出，浏览器会把未知的 input 类型
回退为 `text`，这会在不支持功能的浏览器里暴露明文；未知的自定义元素则不会悄悄变成可编辑文本
框。polyfill 把元素写作 `<sealed-input>`，原生草案写作 `<sealedinput>` 或近似的标准名称。不支持
或配置错误时，控件应保持禁用，不允许回退到明文输入
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

设计里有两个职责不同的 origin。嵌入方 origin 拥有文档和表单；接收方 origin 来自表单目的地，
在 `/.well-known/sealed-input` 发布密钥信息，并持有私钥。polyfill 使用的隔离 frame 也由该接收方
origin 提供。explainer 认为，这样不会把 polyfill 供应商或 CDN 变成另一个能看见输入值的参与方
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

现有 CSP 控制是这条边界的一部分。接收方可以用 `frame-ancestors` 限制哪些页面嵌入 frame；嵌入
页面可以用 `frame-src` 和 `form-action` 限制 frame 与表单目的地。接收方密钥按解析后的表单
action 查找，页面脚本不能直接提供密钥。因此替换加密目的地也需要改变这些策略已经约束的目标
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

草案信封把密文绑定到嵌入方 origin、去掉 query 与 fragment 的 action URL，以及字段名。这些值
作为附加认证数据参与加密；接收方若按另一个槽位重建数据，就无法打开信封。草案格式还携带格式
版本和密钥标识，使接收方可以在轮换已发布密钥时选择对应私钥
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

兼容普通表单是明示的设计目标。在 explainer 中，value getter 返回加密信封，`FormData` 取得的
也是该信封，服务器再用接收方库打开它。约束检查在受保护边界内执行，只向页面暴露通用的有效性
结果。草案压制可能携带明文的事件与选择区接口，同时保留它所描述的 focus、reset、disabled 与
表单提交行为（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

## 原型已经验证了什么

WICG issue 记录了两个使用同一信封格式的实现。其一是 form-associated custom element polyfill，
在接收方提供的 frame 内加密；其二是一组 Ladybird patch，包含原生元素与 `sealed-fields` 指令。
issue 表示，同一个服务器实现可以打开两种实现产出的信封，engine 测试则覆盖元素路径与由 header
交付指令的路径（[WICG 提案 issue](https://github.com/WICG/proposals/issues/307)）。

原生可行性工作重点检查键入数据可能泄漏的接口。提案作者报告了 clone、切换 input type、paste
事件、控件移除后重新插入、编辑命令，以及字段名或表单 action 改变后的编辑历史等测试。这些是
Ladybird 原型提供的证据，并不是对已发布 Chromium、Firefox 或 WebKit 行为的陈述
（[Ladybird 原生可行性备忘](https://github.com/madeit-build/koschei/blob/main/docs/research/native-feasibility-ladybird.md)）。

polyfill 与原生控件的边界不同。explainer 表示，iframe 能把击键与页面脚本隔离，但无法复现
所有需要浏览器引擎配合的保证。文档点名 autofill 行为、扩展的执行环境与 renderer heap 隔离等
差异。原生提案还包含无法由 JavaScript polyfill 提供的 CSP 行为
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

提案没有宣称密封字段可以阻止所有表单攻击。它把已失陷接收方、同一槽位的重放和发送者认证列为
非目标，也讨论了注入代码显示普通输入框的诱饵字段攻击。拟议 CSP 指令会按 `autocomplete` token
要求密封，但 explainer 明确表示这只是缩小诱饵攻击的空间，并没有彻底关闭它
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

失败方式同样是设计的一部分。well-known 文档缺失或无效、没有可用密钥、frame 被阻止，或目的地
不安全时，控件应保持禁用。explainer 把这种行为描述为有意的可用性取舍，因为回退到明文会直接
破坏所追求的机密性。接收方的静态资源可用性和密钥轮换因而进入表单提交路径
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

<span id="这对-pwa-开发者为什么重要"></span>

## 密封字段提案对表单库和接收端的影响

PWA 与其他 Web 应用一样，可以包含分析脚本、客服组件、应用依赖和表单库。这项提案约束文档
与提交路径，不依赖应用采用哪种安装模式。如果未来形成标准，它将提供一种声明式区分：一类值允许应用以明文
处理，另一类值只应以绑定接收方的加密信封穿过应用代码。这正是 explainer 陈述的核心目标
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

表单集成细节会直接影响既有代码。让 `.value` 与 `FormData` 返回密文，是为了维持把字段值视为
不透明字符串的提交和表单库流程；与此同时，从脚本设置值应失败，约束信息也被刻意压缩。评估该
提案时，需要检查应用是否假定自己可以通过普通 input API 填充、检查、验证、记录或恢复所有字段
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

产品文案也必须留在威胁模型内。提案试图让页面级读取者与接收方之前的设施接触不到明文。它没有
表示解密后的值仍受保护，没有认证输入者，也没有保证注入代码无法展示欺骗性界面。因此，把它概括
为普遍防御表单窃取，会超出 explainer 支持的结论
（[密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)）。

标准审查仍处于早期。Mozilla standards-position 请求于 2026 年 10 月 14 日创建，状态为
unscreened；请求内容希望审查诱饵字段论证和可能遗漏的侧信道。WICG issue 还链接了 WebKit 的
standards-position 请求。这两项请求都不能证明浏览器已经支持，也不能证明已形成共识
（[Mozilla standards-position 请求](https://github.com/mozilla/standards-positions/issues/1468)）。

规划生产部署时，眼下只能用提案梳理安全边界，还无法据此直接部署。提案说明了谁选择接收方、明文
预期出现在哪里、普通表单接口拿到什么，以及哪些错误应让控件关闭。原型为审查提供了可运行材料，
但仍在进行的标准立场工作意味着应用不能把该元素或指令当作可互操作的 Web 平台契约
（[WICG 提案 issue](https://github.com/WICG/proposals/issues/307)）。

## 站内相关条目

- [Web app manifest](/zh/reference/manifest/)：manifest 的成员与处理模型见此条目。
- [Service workers](/zh/reference/service-worker/)：Service Worker 的注册、生命周期与请求处理见此条目。
- [By feature](/zh/compatibility/by-feature/)：按能力浏览 OpenPWA 兼容性数据见此条目。

## 待核实

- 这项提案是否会进入标准轨道规范，尚未确认。
- Chromium、Firefox 或 WebKit 是否会实现该元素或 CSP 指令，尚未确认。
- 最终元素名称、信封格式、发现协议与事件接口，尚未确认。
- 审查者是否接受其对诱饵字段和可观察侧信道的处理，尚未确认。
- 原生实现如何接入各引擎的 autofill、无障碍、编辑与扩展架构，尚未确认。
- 原型记录的性能和可用性取舍能否适用于生产设备与接收方部署，尚未确认。

## 参考来源

- [密封表单字段提案](https://github.com/WICG/proposals/issues/307)（github.com）
- [密封表单字段 explainer](https://github.com/madeit-build/koschei/blob/main/docs/specs/explainer.md)（github.com）
- [Ladybird 原生可行性备忘](https://github.com/madeit-build/koschei/blob/main/docs/research/native-feasibility-ladybird.md)（github.com）
- [Mozilla standards-position 请求](https://github.com/mozilla/standards-positions/issues/1468)（github.com）