安全
浏览器的攻击面分成两部分:不是我们写的引擎,和我们自己写的外壳。两者的表现差别很大,所以我们分开来讲。这个版本已知的缺口在页面末尾。
引擎:Chromium、V8、Skia
整个 2026 年,Chrome 修复了数十个内存安全漏洞,其中六个是已被在野利用的零日漏洞。这些代码不是我们写的,我们也无法修复;这里唯一的防线就是让引擎保持最新。
所以我们的规矩很直白:Girginos Browser 不会基于已到生命周期终点的 Electron 版本发布。Electron 只支持最近的三个主版本,每次发布前都会检查所固定的版本号。目前使用的是 Electron 44.2.0 和 Chromium 152.0.7977.76。
外壳:我们自己写的代码
外壳这一侧的架构决策如下:
- 每个标签页都是一个独立的 WebContentsView。页面内容以 sandbox: true、contextIsolation: true 和 nodeIntegration: false 运行,并且不加载 preload。
- 界面窗口同样在沙箱中运行,并与标签页共用一个会话,因此界面自身发出的请求也会经过拦截器并带上 DNT 请求头。
- IPC 通道只接受来自界面窗口主框架的消息。写入设置时会校验键名和类型。
- 下载项通过标识符寻址;来自界面的原始文件路径永远不会被打开。
- 由页面发起的导航只能是 http(s) 和 view-source:http(s)。file: 和 chrome: 只有在用户自己输入到地址栏时才会打开。
- 移交给外部应用被限制在一份很窄的协议清单里:mailto:、tel:、sms:、magnet:、ftp(s):、webcal:。同一时间只会弹出一个确认框。
- 不透明来源,也就是 origin 为 null 的来源,例如 data: 和 about:,在权限请求中一律拒绝。
- 拼写检查是关闭的,因为 Chromium 会从 Google 的服务器下载词典文件。
- 数据通过临时文件加重命名的方式原子写入。
攻击手法与应对措施
| 类别 | 示例 | 应对措施 |
|---|---|---|
| 地址栏伪造 | RLO/bidi, CR-LF, NUL, bank.com@evil.com, 空白填充、IDN 同形字 | 不可见字符和空格保持编码形式,凭据被隐藏,显示 punycode |
| 域名遮掩 | accounts.google.com.giris.evil.com | 可注册域名以深色显示,其余部分淡化 |
| 冒充内部页面 | newtab.html, 一份下载下来的副本 | 要求完整地址精确匹配,不做子串查找 |
| 全屏界面伪造 | 页面进入全屏并画出一个假的工具栏 | 页面视图永远不会被放大到覆盖外壳 |
| 协议逃逸 | file:, chrome:, blob:, view-source:file: | 页面发起的导航只允许 http(s) |
| 调用外部应用 | ms-msdt:, search-ms:, ms-appinstaller: | 很窄的允许清单,且只有一个确认框 |
| 下载文件名花招 | evil.exe / evil.exe., 结尾的点和空格、用 RLO 隐藏的扩展名 | 在检查扩展名之前先做规范化,最终依据磁盘上的真实文件名判断 |
| 绕过拦截器 | izleyici.com., 结尾的点 | 对主机名做规范化 |
签名的更新链
威胁模型假设更新服务器可能已经被攻陷。顺序是这样的:
- 拉取签名清单以及它旁边的签名文件。
- 用应用内置的 Ed25519 公钥,对清单的原始字节校验签名。校验不通过,就不会读取其中任何一个字段。
- 应用版本闸门:拒绝降级;清单若已过了自己的到期时间同样拒绝——这是为了防止攻击者一直提供旧清单、把更新冻住;必要时强制先经过一个中间版本;下载地址必须是 https。
- 下载器找到的版本和安装包摘要,必须与签名清单中的完全一致。
- 下载完成后,把安装包的 sha512 摘要与签名中的摘要做恒定时间比较。
- 只有在用户确认之后才会开始安装。
任何一步失败,更新就不会进行。私钥从不放在服务器上;即便服务器被攻陷,攻击者也造不出一份有效的清单。
测试
有 118 个单元测试、73 个攻击手法回归测试和 46 个更新校验测试在运行,界面与主进程之间的 IPC 和 DOM 约定也会单独测试。除此之外,每次发布前后还会针对真实产物和线上服务器运行端到端校验脚本。
已知的缺口
以下这些在 0.1.0 中还没有。把它们藏起来会让产品显得比实际更安全,所以我们直接写出来。
- 没有 Mark-of-the-Web
- 下载的文件不会写入 Zone.Identifier,因此 Windows SmartScreen 不会对这些文件生效。浏览器自己有一个警告框,但缺少操作系统这一层。
- 没有代码签名证书
- 安装包的代码签名无法验证。签名清单在更新环节堵上了这个口子,但首次安装仍然是敞开的。
- 没有 Public Suffix List
- 在 github.io 这类托管域名上,网站例外和地址栏高亮覆盖的范围比应有的更宽。
- 证书错误沿用 Chromium 的默认处理
- 我们没有写自定义的「仍要继续」页面;证书有问题时页面就是打不开。
- 拦截只到域名这一层
- 藏在 CNAME 记录后面的追踪器和由第一方提供的广告都抓不到,也不做元素隐藏过滤。