理解 Chromium 中的 Rule-Of-2

2025-03-19 pv

性能、可靠、安全,是现代软件开发的理想目标。

尽管通常不可兼得。

就像 CAP 理论描述的那样,理想丰满,现实骨感。

这三者中,安全往往是最容易被忽略的

我想原因大概有两个。

一是安全事件发生频率低,很少引起重视。

另外,完备的基础设施,例如 HTTPS,现代浏览器,屏蔽了大部分风险,导致很多人误以为网络世界很安全。

其实无论何时,在开发中,防御(Defensive)的意识都要有。

在微软内部,安全的课程每年都会更新,而且反复强调。

毫无疑问,网络世界很复杂,隐藏在暗中的攻击者,去中心化的匿名组织,数以百亿的用户访问,如何保证普通用户和服务的安全?

Chromium 提出了一套简单且通用的 Rule Of 2 准则。

1. 概念

The Rule Of 2 的概念非常简单,就是:

  1. 不可信输入(Untrusted Inputs)
  2. 不安全编程语言(Unsafe implementation language)
  3. 高特权(High Privilege)

如果实现中同时包含三者,将会非常危险!

因此建议,最多包含其中两者。

不可信输入有两种:不可信输入内容,以及不可信输入源。

浏览器每天需要访问形形色色的网站,加载第三方脚本,没有办法假设它们都是安全的。

可信的输入源,通常被认为是安全的。不过按照 Zero Trust 的思路,仍然需要验证

不安全编程语言指的就是内存不安全,例如 C/C++、汇编语言等。内存安全语言,有 Go、Rust、Python 和 Java 等。

根据微软 2019 年的 报告🔗

每年通过安全更新解决的漏洞中,约 70% 仍然是内存安全问题。

这与 Chromium 的 bug tracker 结果基本一致(截止 2019 年 3 月,130 个公开的严重漏洞中,只有 5 个明确与内存安全无关)。

高特权,意味着拥有自由访问底层资源的能力,例如网络、文件系统、摄像头等。

一方面,权限越高,可做的事情越多,反过来,一旦出错,危害也更大。

2. 实践

Chromium 在 2023 年 8 月 宣布🔗,将默认采用 HTTPS。

从源头屏蔽掉不可信输入源。

归一化(Normalization)可以解决不可信输入内容的问题。

通俗地讲,就是将恶意输入转换为一套固定形式,从无限空间映射到有限空间。例如将 URL 转换为 GURL,一种通用的 URL 表达方式。

Chromium 的大部分代码都是用 C++ 写的,不过有很多内存安全语言已经被允许使用:

  • Java(仅限 Android)
  • Swift(仅限 iOS)
  • Rust🔗(供 第三方使用🔗
  • JavaScript 或 WebAssembly(目前不允许在高权限进程中使用)

QR 码生成器🔗 QR 码生成器 Chromium 中使用跨平台内存安全 Rust 库的一个示例。

Chromium 本身是 多进程架构🔗,这种多进程可分为纵向和横向两部分。

纵向的,JavaScript 等外部脚本在 Render 进程执行,而 Render 进程是一个 沙盒进程🔗,如访问文件、网络请求等,需委托拥有更高权限的进程。

横向的,Chromium 有站点隔离策略(Site Isolation),不同站点分属不同的 Render 进程,资源不共享,其中一个进程 Crash,也不会影响其他站点的正常访问。

3. 借鉴

起初我在思考这个问题的时候,毫无头绪,认为网络上各种 case 都有可能发生,几乎不可能保证不出问题。

The Rule Of 2 很好地诠释了什么是化繁为简。

用简单的原则,对冲复杂的问题,找到第一性原理。这是给我的第一点启发。

与计算机一样,浏览器就做了三件事:

  • 输入(Input)
  • 执行(Execute)
  • 输出(Output)

在我看来,这里就对应了 Rule Of 2 里的三点。

  • 输入不可靠
  • 执行可能出问题
  • 输出会带来危险

只要打破其中一个,风险链条就断了。

代码中的 bug 不可避免。头疼医头,脚疼医脚,疲于奔命,不解决本质问题。要正本清源,在设计阶段就体现安全意图

这是我的第二点思考。

4. 总结

Rule Of 2 看似简单,实则背后有着对安全问题的本质思考。

抽象能力,是高级程序员,与普通程序员的最大区别

(完)

参考

  1. CAP 定理 - 维基百科,自由的百科全书🔗
  2. Chromium Docs - The Rule Of 2🔗
  3. 归一化方法 _百度百科🔗
  4. 进程沙盒 | Electron 框架🔗
  5. Site Isolation🔗
在 GitHub 上编辑本页面

最后更新于: 2025-04-08T01:48:11+08:00