在 Chromium 内核开发中,WebUI 是浏览器原生 UI 的重要组成部分,它既提供了诸如 chrome://settings、chrome://downloads 等页面的交互能力,又承担了浏览器安全与权限保护的重任。对于很多开发者来说,src/ui/webui/resources 目录看似只是一个“公共 JS / CSS 库”,但实际上,它承载了 Chromium WebUI 的安全、运行时和基础设施职责,是 WebUI 生态的“宪法”。
本文将从历史背景、架构定位、运行机制、安全模型、以及它与业务模块的交互方式等五个层面,做一次工程级深度剖析。
一、历史与背景:为什么会有这个目录?
1️⃣ WebUI 的原始问题
Chromium 的 WebUI 页面是用 HTML / JS 实现的,但它有一个天然矛盾:
-
运行在 Browser Process:意味着拥有极高权限。
-
能调用 Mojo / C++ / 系统能力:比如直接操作密码、下载文件等。
-
天然 XSS 风险:一旦 HTML 被注入恶意内容,整个浏览器都可能被攻破。
在 Chrome 30~40 年代,WebUI 页面非常“野”,常见问题包括:
-
i18n 字符串直接 innerHTML 插入页面;
-
翻译文件可能被翻译人员加入
<a><img><script>等 HTML 标签; -
多语言文件由外包维护,安全审计难度大;
-
历史上真实发生过安全事故,浏览器被打穿。
2️⃣ Chromium 的战略选择
为了解决这个安全矛盾,Chrome 团队做出了工程化的决定:
WebUI 必须被当成浏览器内核的一部分,而不是普通网页。
因此诞生了 src/ui/webui/resources:
-
定位:WebUI 的“标准库 + 安全基线 + UI 基础设施”。
-
职责:为所有 WebUI 页面提供统一运行时、i18n 安全处理、DOM 子集约束等功能。
它不是具体业务模块,而是WebUI 的运行时基础设施。
二、架构定位:它在 WebUI 中的角色
1️⃣ 它不是业务代码
src/ui/webui/resources 并不属于业务模块,例如:
-
chrome://settings -
chrome://password-manager -
chrome://downloads
而是所有 WebUI 页面共同依赖的 runtime。可以类比为:
| 类比对象 | 对应 |
|---|---|
| C++ STL | WebUI runtime |
| libc | 浏览器 WebUI 基础层 |
| Blink 对 DOM 的限制 | WebUI 对 HTML 的限制 |
2️⃣ 典型目录结构
src/ui/webui/resources/
├── js/
│ ├── parse_html_subset.js ⭐ 安全核心
│ ├── i18n_mixin.js ⭐ i18n 入口
│ ├── cr.js ⭐ 框架 glue
│ ├── util.js
├── cr_elements/ <cr-button> 等
├── css/
├── images/
-
parse_html_subset.js:WebUI 核心安全裁判。 -
i18n_mixin.js:i18n 文案加载和安全插入。 -
cr.js:模块定义和初始化 glue。 -
cr_elements:基础 WebUI 元素组件库。
三、核心机制:它是如何“裁判”的?
1️⃣ 核心设计思想
WebUI 不允许自由 HTML,只允许受控 HTML 子集。
-
由
parse_html_subset.js定义白名单; -
任何超出范围的 HTML 会被拒绝或抛异常。
2️⃣ parse_html_subset.js 的功能
-
允许的 tag:
<b> <i> <br> <p> <a> <span> -
允许的 attribute:
<a href>、<span class> -
禁止的内容:
<script>、<img>、onClick、onLoad、任意未知 tag -
禁止 style:默认禁止
style="background:url(...)"
3️⃣ 运行流程示例
业务调用链:
i18nAdvanced
└── sanitizeInnerHtml
└── sanitizeInnerHtmlInternal
└── parseHtmlSubset
-
业务模块 调用 i18nAdvanced 生成 HTML;
-
resources 强制 sanitize;
-
超出白名单 → 抛异常。
注意:这是设计行为,不是 bug。
四、i18n 的安全模型
1️⃣ 为什么 i18n 是重点对象
i18n 字符串来自 .grdp / .xtb 文件,由非工程师翻译。历史上存在翻译文件加入 <img> 或 javascript: 的情况,直接威胁浏览器安全。
2️⃣ i18n API 设计
| API | 用途 |
|---|---|
i18n() | 纯文本(安全) |
i18nAdvanced() | 限制 HTML(经过 parse_html_subset) |
3️⃣ 为什么 password_manager 常出异常
常见雷区:
-
<a target="_blank">→target不在白名单 -
<br/>→ 自闭合形式 -
<span style=...>→ style 禁止 -
<strong>→ 不在白名单
资源层抛异常是为了集中、早期发现问题,而不是“resources 有 bug”。
五、resources 如何与业务模块交互
1️⃣ 架构模型
Browser Process (C++)
├── WebUIController
├── WebUIMessageHandler ◄── Mojo / IPC
└── DataSource (strings)
│
│ JS bindings (chrome.send / mojo)
WebUI 页面(业务模块)
├── password_manager.js
├── settings.js
└── downloads.js
▲
│ import / mixin
i18nAdvanced()
cr.js
parse_html_subset.js
└─────────────┬──────────────┘
src/ui/webui/resources (runtime / infra)
-
调用方向:业务 → resources;
-
资源目录不主动通信;
-
它是 WebUI 的 runtime / 标准库。
2️⃣ 三种交互方式
1️⃣ Mixin / Base Class 注入
export const I18nMixin = (superClass) => class extends superClass {
i18n(id, ...args) {
return loadTimeData.getString(id, args);
}
i18nAdvanced(id, ...args) {
return sanitizeInnerHtml(
loadTimeData.getString(id, args));
}
};
-
业务模块继承 mixin;
-
runtime 改变行为;
-
编译期 + 运行期融合。
2️⃣ 全局函数 / 约定
-
sanitizeInnerHtml -
parseHtmlSubset -
cr.define() -
loadTimeData
提前注入 WebUI JS 全局,可视为“系统调用接口”。
3️⃣ WebUIDataSource + JS runtime 协作
-
C++ 侧注入字符串:
WebUIDataSource::AddLocalizedString -
JS 侧通过
loadTimeData.getString()获取; -
i18n / i18nAdvanced 基于 resources 提供的 runtime 处理。
C++ 不直接和业务 JS 通信,resources 是中介层。
六、为什么不让业务模块直接通信?
-
防止野生前端:自由 innerHTML → XSS 风险
-
统一 runtime:保证安全模型一致
-
统一通信方式:集中管理 C++ / Mojo 调用
七、和 C++ / Mojo 的关系
-
resources 不直接调用 Mojo;
-
不 import 业务接口;
-
它只提供封装、约束和防护。
业务模块需要调用 C++ / Mojo,必须走 WebUIController + WebUIMessageHandler → Mojo → resources 提供的 runtime 接口。
八、工程级总结
-
src/ui/webui/resources是 WebUI 的“宪法”,业务模块只能遵守,不能挑战。 -
它提供 runtime / 安全裁决 / i18n 支持,但不主动通信。
-
所有异常堆栈指向它,是“最后门卫”,而不是问题根源。
-
修改它必须谨慎,否则破坏浏览器安全模型。
九、工程建议
-
遇到 WebUI 页面抛异常,不要改 resources;
-
修正 业务文案 或降级 i18nAdvanced → i18n;
-
避免非法 HTML,遵循 parse_html_subset 白名单。
十、附录:核心目录与机制复盘
| 文件 | 功能 |
|---|---|
parse_html_subset.js | HTML 白名单裁决 |
i18n_mixin.js | i18n / i18nAdvanced 封装 |
cr.js | 模块 glue,注册全局定义 |
util.js | 常用工具函数 |
cr_elements/ | <cr-button> 等 WebUI 基础组件 |
css/ | 公共样式 |
images/ | 公共资源 |
调用顺序:
-
业务 JS 生成 HTML 文案 → i18nAdvanced()
-
parse_html_subset.js 校验合法性
-
sanitizeInnerHtml 处理异常
-
注入 DOM
十一、工程师视角结论
-
业务模块 = 用户
-
resources = 系统调用接口 + runtime + 审查机制
-
parse_html_subset = 内核裁决
理解这一点,你才能:
-
不再误认为 resources 是“功能模块”
-
正确定位问题根源在业务文案或调用方式
-
安全地扩展 WebUI 功能
🔥 工程金句
src/ui/webui/resources是 WebUI 的宪法,业务模块只能遵守,不能挑战。
parse_html_subset.js 是 WebUI 的内核裁决,不是 bug 根源。

5万+

被折叠的 条评论
为什么被折叠?



