// 安全研究 · 2025-08-26

为什么 root 用户运行某些应用必须加 --no-sandbox

在 Linux/Docker 场景里,以 root 身份启动 Chrome、Chromium、Electron 甚至 AppImage 时,经常会遇到

Running as root without --no-sandbox is not supported

于是大家被迫加上 --no-sandbox 才能继续。这串神秘参数到底是什么意思?为什么 root 用户就不能乖乖用默认方式启动?禁用沙盒又会带来什么风险?本文用“原理 → 原因 → 风险 → 解决”四个层次,一次性把来龙去脉讲清楚。


1. 沙盒(Sandbox)是什么?

类比 说明
儿童沙坑 孩子只能在沙坑里玩,不能跑到马路上
浏览器沙盒 渲染进程(网页、JS、插件)只能访问受限资源,即使被攻破也伤不到系统

技术实现
Chromium/Electron 的多层沙盒由以下组件共同完成:

  1. Namespace + Cgroups —— 把进程关进“容器”
  2. Seccomp-BPF —— 用白名单过滤系统调用
  3. SUID 沙盒二进制(chrome-sandbox)—— 早期实现,需 root 权限一次后立刻降权
  4. User namespaces —— 让普通用户也能“假装 root”,从而创建沙盒

简单来说,沙盒的目的是最小权限原则:
“能渲染网页就行,别碰我的硬盘、摄像头、内核模块。”


2. 为什么 root 用户“天然”与沙盒冲突?

2.1 User namespaces 的限制

Linux 内核从 3.8 起支持 user namespaces,但默认只有非特权用户才能创建它(内核参数 kernel.unprivileged_userns_clone=1)。
root 用户若再去申请 user namespace,会触发权限悖论:
“我已经有所有权限了,为什么还要再套一层假权限?”
于是 Chromium 干脆拒绝启动,避免实现复杂化。

2.2 SUID sandbox 的“自废武功”

早期 Chromium 依赖一个 setuid root 的 helper 二进制 chrome-sandbox 来启动第二层沙盒。
如果你本身就是 root,这个 helper 无法安全地再次降权,导致初始化失败。

因此,代码里直接写了:

if (getuid() == 0 && !command_line->HasSwitch("no-sandbox")) {
  LOG(FATAL) << "Running as root without --no-sandbox is not supported.";
}

3. --no-sandbox 做了什么?

参数 作用 后果
--no-sandbox 完全关闭所有沙盒层 渲染进程 = root 权限;网页 JS 可执行任意系统调用
--disable-setuid-sandbox 仅关闭老旧的 SUID helper,仍保留 namespace/seccomp 风险次之;部分环境可用

一句话:
--no-sandbox 把浏览器从“安全童车”里拽出来,直接放到高速公路中央。


4. 实际场景:为什么大家还是“被迫”用它?

场景 触发条件 常见“解决”帖子
Docker 容器内跑前端测试 默认 root 用户 + 精简镜像无 chrome-sandbox 文件 “加 --no-sandbox 就好了”
CI/CD 跑 headless Chrome GitLab Runner 以 root 起服务 同上
VPS/云服务器爬虫 图方便直接用 root 起 Puppeteer 同上

这些文章只给药方,不说副作用,导致 --no-sandbox 像“万能钥匙”一样泛滥。


5. 真实风险:一失足成千古恨

5.1 远程代码执行(RCE)

攻击者构造一个恶意网页,利用 V8/webkit 漏洞,在渲染进程内拿到 shell;
没有沙盒 → 渲染进程就是 root → 直接控制宿主机。

5.2 容器逃逸

Docker 内即使加了 --cap-drop 也没用:root 进程已突破第一层隔离。

5.3 持续化 & 横向移动

攻击者可写 crontab、替换系统二进制、在内网横向扫描,危害从“一个容器”升级为“整个集群”。


6. 正确做法:既安全又跑得起来

方案一:创建专用普通用户(推荐)

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y chromium-browser
# 创建非特权用户
RUN useradd -m -s /bin/bash chrome
USER chrome
ENTRYPOINT ["chromium-browser", "--headless", "--disable-gpu"]
  • 无需 --no-sandbox
  • 天然支持 user namespaces
  • 与宿主机 root 隔离

方案二:保留 root,但补足沙盒依赖

若必须 root(如某些 K8s securityContext 限制):

  1. 确保镜像里包含 /opt/google/chrome/chrome-sandbox 并 4755 root:root
  2. 或在内核开启 kernel.unprivileged_userns_clone=1 后,用 --disable-setuid-sandbox
  3. 配合 Seccomp/AppArmor 做二级加固

方案三:使用官方提供的 chrome-headless-shell

Google 从 2024 年起提供专门为 CI/CD 设计的轻量 headless 版本,默认关闭 GPU、扩展,且支持非 root 沙盒。


7. 结论与最佳实践 checklist

✅ 做 ❌ 不做
为浏览器/爬虫创建专用非 root 用户 图方便 root + --no-sandbox
最小化镜像,仅含 chrome 与依赖 把整编桌面 Chrome 塞进容器
定期跟随官方升级,修复渲染引擎漏洞 一个镜像跑一年,漏洞满天飞
在 K8s 里加 securityContext.runAsNonRoot: true 默认 runAsUser: 0

原文 https://blog.csdn.net/2301_79518550/article/details/150720868