Simon Willison 这个小实验,钩子很小,问题很大:不可信的小应用到底该不该联网?

全禁,很多应用直接残废。全开,平台等于把出网权限交给一段自己未必看过的代码。他做的事,是让沙箱在两者之间多出一个动作:问一句。

实验里,应用被放进受 CSP 保护的 sandboxed iframe。默认策略是 default-src 'none',也就是先全部关掉。沙箱里的代码尝试 fetch() https://api.inaturalist.org 时,被 CSP 拦下。自定义 fetch() 把这个失败信息传给父页面,父页面弹窗询问:要不要把这个 origin 加入 connect-src 白名单?用户同意后,刷新页面,规则生效。

这里没有“逃逸”。没有“绕过 CSP”。只有宿主系统按规则开门。

它具体跑通了什么

这套流程的价值,不在代码多复杂,而在边界清楚。

CSP 负责拦。sandboxed iframe 负责隔离。自定义 fetch() 负责把一次失败变成可解释事件。父页面负责授权。connect-src 白名单负责控制能连哪里。

环节实验里的做法真正的含义
默认策略default-src 'none'先拒绝,不预设信任
运行环境sandboxed iframe把第三方 HTML / 小应用关进容器
联网请求沙箱内 fetch() API只讨论特定出网行为,不是所有能力
拦截对象https://api.inaturalist.org按 origin 授权,而不是一口气放开网络
授权动作父页面弹窗询问是否加入 connect-src权限决定交给宿主层
生效方式加白名单后刷新不是即时魔法,仍受页面生命周期限制

这个点很适合几类人看:插件平台开发者、低代码工具开发者、AI 代码沙箱维护者、UGC HTML 托管平台。

这些产品每天面对同一个麻烦:用户想运行别人写的小应用,小应用又经常要调外部 API。平台如果只给“允许全部网络 / 禁止全部网络”两个选项,最后一定会被产品需求逼到墙角。

这个实验给的是第三种姿势:默认关门,按 origin 开门,开门前说明门外是谁。

这对平台开发者有什么用

我更在意的是,它把 CSP 从一条冷规则,拉近到一个权限交互。

这有点像早期操作系统的权限弹窗。应用要访问相机、通讯录、定位,系统先问用户。类比不完全一样:CSP 是页面声明的安全策略,不是浏览器原生权限框架;Simon 这个也是实验,不是标准能力。

但治理思路接近:危险动作不要藏在日志里,要浮到宿主界面上。

对做 AI 代码沙箱的人,这尤其现实。AI 生成的小应用会越来越多,平台不可能逐行审查每个 fetch()。更靠谱的做法,是把出网目标拆出来,让用户或宿主判断:这个小应用为什么要连这个 origin?它是不是当前任务需要的?

对插件平台和低代码平台,动作也很具体:

  • 原本打算默认放开网络的团队,至少该考虑按 origin 授权。
  • 原本一刀切禁用外部 API 的团队,可以评估这种“申请—批准—刷新”的流程。
  • 如果平台面向企业用户,白名单最好能由管理员预设,而不是让每个终端用户临场点 OK。

“明者防祸于未萌。”放到这里,就是不要等小应用已经拿到任意出网能力,再假装靠审计补救。先把联网目标亮出来,很多风险才有被讨论的入口。

不过,别把提示框当安全银弹。

用户点 OK,不等于用户理解风险。授权疲劳会吞掉很多好设计。一个 origin 看起来正常,不代表 API 行为永远可控;一个 API 今天合理,不代表明天不会被滥用。

更硬的限制也在这里:这个实验主要处理 fetch() / connect-src 这一类联网请求。它不解决所有 iframe 安全问题,也不能替代内容隔离、权限边界、日志审计和滥用处置。

还有几个采用前必须想清楚的问题:白名单放在哪里?按用户、按项目,还是按组织?谁能撤销?弹窗文案怎么写,才能让用户知道这次授权影响什么?如果恶意代码反复触发授权请求,平台怎么限流?

这些不是细枝末节。权限系统死掉,通常不是死在拦不住,而是死在问得太多、问得太含糊。

接下来该看哪几件事

这个实验目前最值得观察的,不是它会不会马上变成生产框架,而是这种模式能不能被产品化。

我会看四个变量。

观察点为什么重要
CSP 错误捕获边界包装 fetch() 能覆盖多少场景,哪些请求不会走这条链路
白名单持久化授权如果不能管理、撤销、分层,就会变成一次性弹窗
企业控制台真正的生产平台往往需要管理员策略,而不是只靠用户点击
滥用防护恶意小应用可以制造授权疲劳,平台必须限制提示频率和展示上下文

这里的分水岭很清楚。

如果它只是弹窗加白名单,那只是一个顺手的小工具。如果它能和项目权限、组织策略、审计日志、撤销机制连起来,就会变成 Web 小应用容器的一块基础设施。

安全沙箱最怕两种懒惰。

一种是安全团队只会说“不”。产品最后会绕开它。

另一种是产品团队只会说“先放开”。事故最后会找回来。

这次实验少见地把中间地带做得很具体:默认拒绝,按源授权,刷新生效,用户和宿主都看得见。它不宏大,但方向对。

真正难的不是让沙箱更凶,而是让它问得准、记得住、撤得回。