面向多进程浏览器安全架构 / AI Agent 沙箱设计。基于 Chromium 148 系代码。
引言:Chromium 沙箱在防什么
Chromium 的安全不是单一机制,而是两层叠加:
- OS 级沙箱(
sandbox/win/src+sandbox/policy):限制子进程能调用哪些 Win32/NT API、能碰哪些内核对象。 - 逻辑级站点隔离(Site Isolation + ProcessLock):限制渲染进程被攻破后能读到哪些跨站内存。
前者防「逃逸到操作系统」;后者防 Spectre 类同进程侧信道。本文聚焦 Windows 沙箱,后者只在文末点一句边界。
对 AI Agent 沙箱最有价值的映射是:
Broker 定策略 → 子进程高权限启动 → warmup → 不可逆降权 → 敏感 syscall 走 Broker 白名单
一、策略怎么配:定 vs 动
Chromium 不是每个子进程从零算策略,而是:
类型套餐(定) + Feature/命令行/Delegate(动)
配置流水线:
否是GetSandboxType()GenerateConfigForSandboxedProcess()DisableDefaultPolicy?默认 Token / Job / Integrity跳过默认 Token类型分支 Renderer/GPU/Network...Feature / 命令行delegate->InitializeConfig()PreSpawnChild() Embedder 最后一刀Freeze → Policy 缓存 by SandboxTag
Policy 缓存: 同 GetSandboxTag()(如 renderer-jitless!kRenderer)共享一份 frozen config,不是每个进程重算。
二、共用默认策略(除非 DisableDefaultPolicy())
所有走 GenerateConfigForSandboxedProcess() 的子进程,默认都会叠下面四块。
2.1 两类 Mitigation:先宽后严
| 批次 | 何时生效 | 典型项 |
|---|---|---|
|
Pre-startup |
|
DEP、SEHOP、Extension Point Disable、Bottom-up ASLR |
|
Post-startup(delayed) |
子进程 |
|
Renderer 启动要加载 ICU、DWrite、V8 等,限制开太早会 init 失败,所以 warmup 完成后再在 LowerToken() 里锁死。
Pre-startup 要点
| Mitigation | 原理 | 防什么 |
|---|---|---|
|
DEP |
数据页不可执行(NX) |
栈/堆溢出直接跑 shellcode |
|
ASLR 系列 |
栈/堆随机化;禁远程/低完整性 DLL |
ROP、DLL 劫持 |
|
Extension Point Disable |
关 AppInit_DLLs、全局 Hook 等 |
杀软/输入法注入、hook ntdll |
|
SEHOP |
校验 SEH 链(主要 32-bit) |
经典栈溢出利用链 |
|
HEAP_TERMINATE |
堆损坏即终止 |
UAF/堆破坏窗口 |
|
NONSYSTEM_FONT_DISABLE |
禁非系统目录字体 |
字体解析漏洞、GDI 面 |
|
RESTRICT_INDIRECT_BRANCH_PREDICTION |
限制间接分支预测 |
Spectre v2 类 |
|
KTM / FSCTL_DISABLED |
限制内核事务、文件系统控制码 |
缩小 NT/驱动触达面 |
Post-startup 要点
| Mitigation | 原理 | 防什么 |
|---|---|---|
|
DLL_SEARCH_ORDER |
System32 优先等安全搜索顺序 |
当前目录 DLL 劫持 |
|
FORCE_MS_SIGNED_BINS |
只允许 MS 签名 DLL |
降权后第三方注入 |
|
DYNAMIC_CODE_DISABLE |
禁止 RW→RX(W^X) |
无 JIT 进程的 ROP 落地 |
|
STRICT_HANDLE_CHECKS |
无效句柄即崩溃 |
UAF 句柄利用 |
全局动态开关:--allow-third-party-modules 会关掉 MS signed bins;kWinSboxStrictHandleChecks 开严格句柄检查。
2.2 双 Token:启动宽、运行严
Chromium 用两个 token 创建子进程(PolicyBase::MakeTokens()):
CreateProcessAsUserW( lockdown_token ) // Primary = 最终身份
SetThreadToken( impersonation_token ) // 主线程暂时更高权限
… warmup …
LowerToken() → RevertToSelf() // 回到 lockdown
Initial (USER_RESTRICTED_SAME_ACCESS) | Lockdown (USER_LOCKDOWN) | |
|---|---|---|
|
Restricting SID |
All |
NULL(几乎什么都访问不了) |
|
Deny-Only |
None |
所有 group |
|
Privilege |
保留 |
全删 |
|
用途 |
读注册表、加载系统 DLL、ICU/DWrite init |
永久身份;文件/注册表等走 Broker IPC |
SetLockdownDefaultDacl() 还会收紧 token 默认 DACL,让进程自己创建的对象也不宽放。
Integrity: 启动 Low → LowerToken() 后 Untrusted。MIC 是写隔离层:低完整性不能写高完整性对象,token 有洞时仍多挡一层。
2.3 Job Object:kLockdown
Job 管进程组生命周期 + UI/资源,不是 ACL 模型。
| 限制 | 目的 |
|---|---|
|
|
Browser 退出 → 子进程全杀 |
|
|
防 sandbox 内再 fork |
|
|
异常即死 |
|
|
与用户桌面 GUI 隔离 |
|
内存上限 |
防单进程吃光内存(Renderer ~1TB,GPU 8–64GB) |
2.4 AddGenericConfig:问题 DLL 卸载
Broker 扫描自身已加载模块,命中 blocklist(蓝牙、广告、RelevantKnowledge 等)则 AddDllToUnload。子进程在 main/CRT 之前,Interception Agent 执行 INTERCEPTION_UNLOAD_MODULE。
目的不是防高级 exploit,而是防第三方注入在 DllMain 里崩进程或破坏 sandbox hook。
2.5 Alternate Winstation
默认 Desktop::kAlternateWinstation:Broker 建独立 Window Station + Desktop,Renderer 不在 WinSta0\Default。
- 与用户窗口、剪贴板、广播消息隔离
- 配合 Job
UILIMIT_DESKTOP - Desktop integrity 降到 ≤ 子进程 integrity
GPU 故意不用 alternate desktop(否则 GL/UI 死锁)。
2.6 五层防御一览
Mitigation → exploit 难写、难稳定
Token LOCKDOWN → OS 对象默认全拒,走 Broker IPC
MIC Untrusted → 写隔离
Job kLockdown → 进程树 / UI / 内存
Alternate WinSta + DLL Unload → GUI 隔离、注入剔除
不防 Spectre 读同进程跨站数据——那是 Site Isolation 的事。
三、全局动态开关
| 来源 | 效果 |
|---|---|
|
|
整进程不 sandbox |
|
|
不启用 |
|
|
严格句柄检查 |
|
Delegate |
|
|
|
最后统一:delegate->InitializeConfig() → PreSpawnChild()。
四、各进程类型:定 + 动
4.1 Browser
| 定 | 动 |
|---|---|
|
不 sandbox,当 Broker |
|
|
|
无子进程 Delegate |
4.2 Renderer(kRenderer)— 最严
定: 完整默认策略;Win32k lockdown(upstream);关 kKsecDD;Job 内存 64-bit 最高 ~1TB;kWinSboxZeroAppShim 清 PEB shim。
动:
| 来源 | 内容 |
|---|---|
|
命令行 |
|
|
Feature |
|
|
Delegate |
Tag: |
跳过 Win32k lockdown;AllowWindowsFontsDir() 只读 %WINDIR%\Fonts;字体走 DWrite proxy 或 no-sandbox 时 GDI。
4.3 GPU(kGpu)— 中等
定: DisableDefaultPolicy();仍走通用 Mitigation;SetLockdownDefaultDacl + AddRestrictingRandomSid;Job 内存 8–64GB。
动:
| 来源 | 内容 |
|---|---|
|
命令行 |
|
|
Delegate |
Token → |
4.4 Network(Utility 子类型)— LPAC 路线
定: 通用 Mitigation + DYNAMIC_CODE_DISABLE;Job kLockdown;LPAC profile cr.sb.net + SHA1(exe path);InternetClient、PrivateNetwork 等 capability。
动:
| 来源 | 内容 |
|---|---|
|
Delegate |
|
|
Feature |
|
|
其他 |
未 sandbox 仍进 Job( |
Network 用 AppContainer/LPAC 替代 Restricted Token,靠 capability SID 白名单给网络权限。
4.5 Utility 默认(kUtility)
定: 同 Renderer 基线,但无 Renderer 专属 Win32k/ksec;默认允许动态代码(Utility 里跑 V8/wasm)。
动: --utility-sub-type 决定实际子类型;Tag utility!<sandbox_type>;PreSpawnChild()、AddDelegateData 传 preload 库等。
4.6 Service / ServiceWithJit
定: 默认策略 + Win32k lockdown;kService 额外 DYNAMIC_CODE_DISABLE;SetFilterEnvironment(true)。
动: kServiceWithJit → CetCompatible() = false。
4.7 其他 Utility 子类型(速查)
| 子类型 | 定(差异) | 动 |
|---|---|---|
|
Audio |
禁用默认策略;Token → |
|
|
IconReader |
+ |
自定义 Token/Integrity |
|
PrintBackend |
Delegate 自定义 Token |
|
|
PrintCompositor |
可选 LPAC |
|
|
MediaFoundationCdm |
LPAC + Job |
|
|
ProxyResolver |
LPAC |
|
|
OnDeviceModelExecution |
类似 GPU Token + LPAC |
exe path 作 AC id |
|
XR Compositing |
几乎不 sandbox |
专用 config |
|
ScreenAI / SpeechRecognition |
各自定制 |
允许第三方模块 |
五、Renderer 启动到进沙箱:调用链
Browser: RenderProcessHostImpl
→ SandboxWin::StartSandboxedProcess()
→ GenerateConfigForSandboxedProcess() + Delegate::InitializeConfig()
→ SpawnTargetAsync()
→ MakeTokens() + InitJob()
→ CreateProcessAsUserW(CREATE_SUSPENDED) + SetThreadToken(impersonation)
→ InitProcess() // 注入 Interception + Policy 到 shared memory
→ ResumeThread
Renderer: RendererMain()
→ PlatformInitialize() // ICU、DWrite 等(仍较高权限)
→ RenderThreadImpl 构造
→ EnableSandbox()
→ TargetServices::LowerToken()
→ RevertToSelf + 降 Integrity + CloseHandles + delayed Mitigation
任一步失败 → TerminateProcess(SBOX_FATAL_*),fail-closed。
六、与 Site Isolation 的边界
| 机制 | 防什么 |
|---|---|
|
OS 沙箱 |
被控后读文件、提权、碰桌面、加载恶意 DLL |
|
Site Isolation |
被控后读其他站点同进程内存(Spectre) |
Desktop 默认 --site-per-process:不同站点不同 Renderer;Browser 侧 ProcessLock + CanAccessDataForOrigin() 在 IPC 层再拦一道。
七、fork 两点
- Renderer 不做 Win32k lockdown(
USE_HACK)。 - PDF 等可通过
AllowWindowsFontsDir()只读系统字体目录。
主路径记忆:Renderer 最严 → GPU 中等 → Network 走 LPAC → Browser 不 sandbox → Utility 看 sub-type。
八、下一层:NT Interception
Token/Job 默认「全拒」后,文件、注册表等按需放行靠第三道门:
- 子进程
NtCreateFile等被 hook → CrossCall IPC → BrokerPolicyEngine判 Allow/Deny - 规则来自
filesystem_policy、process_thread_policy等,编译进 shared memory
这是 Chromium 区别于「只做 token 裁剪」的核心:默认拒绝 + Broker 白名单。
结语
Chromium Windows 沙箱的设计哲学可以概括为:
- 类型套餐保证可维护、可缓存、可审计;
- Delegate/Feature 在固定框架内做最小差异化;
- 双 Token + delayed Mitigation 平衡 init 与安全;
- Token + Job + Mitigation + Interception 纵深叠加;
- OS 沙箱与 Site Isolation 分工明确,不互相替代。
若你在设计 AI Agent 沙箱,最值得照搬的是 Broker 白名单 IPC 和 不可逆降权时机,而不是简单套一个 Docker 或 seccomp 就完事。
代码路径:sandbox/policy/win/sandbox_win.cc、sandbox/win/src/{broker_services,target_services,job,restricted_token}.cc、content/browser/*/sandboxed_process_launcher_delegate*.cc。
5070



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



