Chromium WebUI 定制实践:从 C++ 注入到 JS 安全展示全链路解析

2025年度报告已生成 2k人浏览 16人参与

的 WebUI 框架,但在定制浏览器、增加功能或修改 UI 时,如果不了解其机制,很容易踩坑。本文将从源码层、架构设计、i18n 安全、定制实践三个维度,深度解析 Chromium WebUI 的运行机制,并提供工程级定制方案,特别针对密码管理(password_manager)模块,确保安全、可维护。


一、loadTimeData:从 C++ 注入到 JS 的全链路机制

WebUI 最核心、最容易被误解的一条路径是 loadTimeData。它承担了 浏览器内核到前端页面的同步数据注入任务,包括字符串文案、布尔值、数字和 feature flag。理解其全链路,是安全定制的第一步。

1️⃣ 宏观视角

一句话总结:

C++ 在页面加载前,把一份只读配置 + 字符串字典注入到 JS 全局对象 loadTimeData 中,JS 只能读,不能写。

2️⃣ C++ 侧:WebUIDataSource(起点)

Chromium 的 WebUI 数据源由 content::WebUIDataSource 提供。以密码管理模块为例:

content::WebUIDataSource* source = content::WebUIDataSource::Create("password-manager"); 

本质上为 chrome://password-manager 创建了一个“虚拟站点数据源”。

(1)注入字符串资源
source->AddLocalizedString( "passwordManagerTitle", IDS_PASSWORD_MANAGER_TITLE); 

底层逻辑:

  1. 记录 key → resource id;

  2. 页面加载时根据语言映射文本;

  3. 最终序列化成 JSON,待 JS 侧读取。

(2)注入布尔 / 数字 / Feature Flag
source->AddBoolean("enableAccountStorage", true); source->AddInteger("maxPasswords", 1000); 

这是定制浏览器最安全的前后端桥梁,无需触碰业务 JS。

(3)绑定到 WebUI
content::WebUIDataSource::Add(profile, source); 

到这一步为止:

  • 没有 JS;

  • 没有 DOM;

  • 仅仅准备数据。


3️⃣ 页面加载时发生了什么

当 WebUI 页面加载:

  1. Chromium 内部生成 JS,将 JSON 注入:

window.loadTimeData = new LoadTimeData({...}); 
  1. 这段 JS 先于业务 JS 执行

  2. 页面 JS 永远拿到已完成注入的对象。

这就是 loadTimeData 名称的由来。


4️⃣ JS 侧 runtime

核心 runtime 文件位于 src/ui/webui/resources/js/load_time_data.js

class LoadTimeData {
  getString(id) {
    return this.data_[id];
  }
  getBoolean(id) {
    return !!this.data_[id];
  }
}
window.loadTimeData = new LoadTimeData(...);

所有业务 JS 都通过 loadTimeData 获取 C++ 注入的数据,而不直接访问底层 JSON。


5️⃣ 使用示例

// 纯文本 const title = loadTimeData.getString('passwordManagerTitle'); 
// i18n 封装 this.i18n('passwordManagerTitle'); 

6️⃣ 为什么不用 Mojo / IPC

方案问题
Mojo异步、复杂、性能损耗
IPC安全模型复杂
loadTimeData同步、只读、安全,最适合静态配置和文案

结论:80% UI 配置 = loadTimeData,20% 动态数据 = Mojo


二、i18n vs i18nAdvanced:设计取舍 & 坑位清单

i18n 系列 API 是 WebUI 文案安全的核心,选择不当会导致 XSS 或页面炸裂。

1️⃣ 设计目标对比

API目标
i18n()100% 安全、纯文本
i18nAdvanced()有限 HTML,但必须可控

2️⃣ i18n() 强烈推荐

this.textContent = this.i18n('title'); 

特点:

  • 自动 escape;

  • 永远不会 XSS;

  • 不允许 HTML。

工程实践中,90% 文案都应使用 i18n()


3️⃣ i18nAdvanced() 高危

this.innerHTML = this.i18nAdvanced('description'); 

内部调用流程:

loadTimeData.getString() ↓ sanitizeInnerHtml() ↓ parseHtmlSubset() 

4️⃣ parse_html_subset 白名单示例

允许标签:

  • <a href>

  • <b>

  • <i>

  • <br>

禁止或高风险:

内容结果
<br/>
<strong>❌(部分版本)
<a target="_blank">
<span style="">
&nbsp;
<img>

总结:能用 i18n 就不要用 i18nAdvanced,i18nAdvanced 仅保留历史兼容或特殊 HTML 场景。


5️⃣ 定制浏览器建议

  • 密码管理、同步、账号页面:

    • 一律禁 HTML 文案;

    • 用 CSS / DOM 组合代替。


三、定制浏览器:安全扩展 WebUI runtime

为了保证定制浏览器安全和可维护,有三种正确扩展方式。


1️⃣ ❌ 绝对不要做的事

  • 改 parse_html_subset.js;

  • 放宽 HTML 白名单;

  • 翻译文件包含复杂 HTML;

  • 业务 JS 开后门。

短期爽,长期炸。


2️⃣ ✅ 安全方式一:C++ → loadTimeData

source->AddBoolean("is360Browser", true); source->AddString("brandName", "360安全浏览器"); 

JS 使用:

if (loadTimeData.getBoolean('is360Browser')) { // 定制逻辑 } 

优点:

  • 无 XSS;

  • 无运行期依赖;

  • 可测试。


3️⃣ ✅ 安全方式二:新增 runtime helper

新增文件 src/ui/webui/resources/js/brand_util.js

export function is360() { return loadTimeData.getBoolean('is360Browser'); } 

业务层使用:

import { is360 } from 'chrome://resources/js/brand_util.js'; 

可维护、安全、分层清晰。


4️⃣ ✅ 安全方式三:WebUIMessageHandler(动态)

适合:

  • 实时数据;

  • 用户操作;

  • 状态变更。

动态数据使用 Mojo / message handler,不用于静态配置。


5️⃣ 推荐分层铁律

C++(配置 / feature) ↓ loadTimeData ↓ JS runtime(resources) ↓ helper / mixin ↓ 业务 WebUI 

永远不要反向依赖。


四、password_manager i18n 重构示例(零炸)

原始文案存在 XSS 风险:

<message name="password_manager_description"> Please <a href="javascript:doSomething()">click here</a> to manage passwords. </message> 

重构策略:

  • 移除危险 HTML;

  • 链接事件绑定而不是 javascript: URL;

  • 使用安全 API。


strings.xtb

<message name="password_manager_description"> Please click here to manage passwords. </message> 

passwords_section.js

ready() {
  const desc = this.i18n('password_manager_description');
  this.shadowRoot.querySelector('#desc').textContent = desc;

  const link = this.shadowRoot.querySelector('#manage-link');
  link.addEventListener('click', () => {
    this.managePasswords();
  });
}

HTML 模板

<div id="desc"></div> <button id="manage-link">Manage</button> 

✅ 安全:

  • 不依赖 innerHTML;

  • 不违反 parse_html_subset;

  • i18n 文案安全;

  • 用户事件绑定明确。


五、工程级总结

  1. 数据流清晰:C++ → loadTimeData → resources → 页面

  2. 安全边界明确:parse_html_subset + i18n / i18nAdvanced

  3. 定制方案

    • 新文案 / feature → loadTimeData + JS helper;

    • 动态数据 → Mojo / WebUIMessageHandler;

    • 不碰 infra,不改 parse_html_subset;

  4. 密码管理 / 同步页面:特别注意 HTML 安全,避免 innerHTML;

  5. 工程规范

    • loadTimeData 只读;

    • i18n 优先,i18nAdvanced 限用;

    • JS runtime 不改动,新增 helper 扩展;

    • Mojo 仅处理动态、异步逻辑。

总结一句话:Chromium WebUI 是“C++ 数据 + runtime 安全 + 业务展示”的闭环,正确理解和分层定制,是工程级浏览器安全和稳定的核心。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ปรัชญา แค้วคำมูล

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值