preview-sandbox/html-preview-sandbox

GitHub: preview-sandbox/html-preview-sandbox

一个用于在浏览器和 Node 环境中安全预览不受信任 HTML 的前端库,通过 DOMPurify 消毒、CSP 策略和沙盒化 iframe 构建多层防御 pipeline。

Stars: 1 | Forks: 0

# html-preview-sandbox [![npm](https://img.shields.io/npm/v/html-preview-sandbox.svg)](https://www.npmjs.com/package/html-preview-sandbox) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/preview-sandbox/html-preview-sandbox/actions/workflows/ci.yml) [![provenance](https://img.shields.io/badge/provenance-signed-brightgreen)](https://www.npmjs.com/package/html-preview-sandbox#provenance) [![license](https://img.shields.io/npm/l/html-preview-sandbox.svg)](LICENSE) 在沙盒化的 iframe 中安全预览不受信任的交互式 HTML。 `html-preview-sandbox` 帮助应用程序渲染不受信任的 HTML 文件、用户上传内容以及 AI 生成的报告,而无需授予它们完整的浏览器权限。它结合了 DOMPurify 消毒、CSP 预设、不透明源的沙盒化 iframe、外部链接中介以及宿主回调。 **[在托管的 Playground 中试用 →](https://preview-sandbox.github.io/html-preview-sandbox/playground/)** ## 安装 ``` npm install html-preview-sandbox ``` ## 快速开始 ``` import { createPreview } from 'html-preview-sandbox'; const preview = createPreview(document.querySelector('#preview'), { csp: 'strict', onOpenExternal(url) { window.open(url, '_blank', 'noopener,noreferrer'); }, onCspViolation(report) { console.warn('CSP blocked:', report); }, onSanitize(report) { console.info('Sanitize report:', report); }, }); await preview.render(fileOrHtmlString); ``` ## 运行时入口点 该包仅支持 **ESM**,并且 Node/默认入口需要 Node 18+。 它通过包导出条件提供独立的 Node 和浏览器构建: - Node/默认导入:使用 DOMPurify 和 jsdom。 - 浏览器导入:使用 DOMPurify 和真实的浏览器 `window`。 - 显式浏览器导入:`html-preview-sandbox/browser`。 大多数现代打包器会自动解析 `browser` 条件。示例和 Playground 运行的是 `dist/index.browser.js`,因此从仓库中打开它们之前,请先构建该包。 当你的运行时或打包器不支持 `browser` 条件时,请使用显式的浏览器子路径: ``` import { createPreview } from 'html-preview-sandbox/browser'; ``` ## 消毒器选择 本项目目前使用 **DOMPurify** 作为消毒层。 - 浏览器运行时:DOMPurify 针对真实的浏览器 `window` 运行。 - Node 运行时:DOMPurify 与 jsdom 一起运行。 - 当前实现中未使用 `sanitize-html`。 DOMPurify 仍然只是一层。预览还依赖于 CSP、沙盒化 iframe、桥接处理、外部 URL 过滤以及可选的宿主导航拦截。 ## 它是什么 - 用于不受信任的 HTML 文件和字符串的客户端预览 pipeline。 - 一种在降低宿主应用风险的同时保留有用交互性的方法。 - 一个包含 Web 示例和 Playground 的小型核心包。 ## 它不是什么 - 不是浏览器:它不浏览 URL 或支持多页面导航。 - 不是附件系统:下载、解密、缓存和权限检查属于宿主应用。 - 不是 DOMPurify 的替代品:消毒只是深度防御 pipeline 中的一层。 - 不能保证所有 HTML 都是安全的:请参阅 `THREAT_MODEL.md`。 ## Pipeline ``` input -> decode -> sanitize -> CSP policy -> bridge -> sandboxed iframe ``` 默认沙盒有意省略了 `allow-same-origin`,从而为预览的文档提供一个不透明的源。外部链接和 `window.open` 调用会通过回调转发给宿主。在纯 Web 环境中,由 JavaScript 驱动的 `window.location` 导航无法被完全拦截;Electron 或其他宿主可以添加更强的导航控制。 能够观察 iframe 导航的宿主集成可以调用 `preview.notifyNavigationAttempt(url)`。核心渲染器将恢复上次受信任的 `srcdoc`,并通过相同的外部链接白名单转发该 URL。 这三个 CSP 预设是按**数据外泄能力**分层的,而不是按它们加载哪些资源分层的: - `offline`:完全无网络。仅限内联 script/style 和 `data:`/`blob:` 资源。 - `strict`(默认):阻止攻击者可读取的数据外泄通道 —— `connect-src 'none'`、`form-action 'none'`,并且没有通配符 `img-src`/`media-src`。可以加载固定的静态 CDN/字体主机,并且允许内联 script 加上 `unsafe-eval`,因为它们除了已允许的内联 script 外没有增加任何攻击者能力,并且没有提供攻击者可读取的数据外泄途径。这并非“零网络” —— 对白名单主机的请求仍会离开本机(参见 `THREAT_MODEL.md` 中的残余风险说明)。 - `balanced`:开放 `https:` 图像/媒体和 `connect-src https:`。这是一个通用的数据外泄攻击面,因此仅将其用于半受信任的内容。 默认情况下,自定义沙盒 token 会被过滤。诸如 `allow-same-origin`、`allow-downloads` 和顶级导航权限之类的高风险 token 会被忽略,除非设置了 `allowUnsafeSandboxTokens`。 外部链接同样是失败即关闭的。默认协议白名单为 `http:`、`https:`、`mailto:` 和 `tel:`。宿主可以通过 `externalProtocols` 缩小其范围,并使用 `allowExternalUrl` 添加域或产品规则。 ## 文档 - [集成指南](docs/INTEGRATION.md) - [使用文档(中文)](docs/README.zh-CN.md) - [安全模型](docs/SECURITY_MODEL.md) - [消毒器决策](docs/SANITIZER_DECISION.md) - [浏览器支持](docs/BROWSER_SUPPORT.md) - [项目结构](docs/PROJECT_STRUCTURE.md) - [分支与发布](docs/BRANCHING.md) - [路线图](docs/ROADMAP.md) - [威胁模型](THREAT_MODEL.md) - [安全策略](SECURITY.md) ## 项目结构 包源代码位于 `src/` 中并构建到 `dist/`。测试和本地示例针对构建输出运行,因此本地检查与使用者收到的包相匹配。 ``` src/ TypeScript package source dist/ Generated ESM bundles and declarations playground/ Local security inspection workbench examples/ Minimal integration examples fixtures/ HTML regression inputs test/ Node and Playwright tests docs/ Integration, architecture, and security notes ``` ## 测试 ``` npm run check:types npm test npm run test:browser npm run build ``` 类型检查会验证 TypeScript 源代码和生成的公共 API 接口。Node 测试套件涵盖了解码、CSP 生成、注入顺序、协议过滤和消毒报告。Playwright 套件验证了真实的浏览器 iframe 沙盒和外部链接桥接,以及 Web 示例、文件上传示例、Web Component 和 Playground 行为。 在 CI 中,在 `npm run test:browser` 之前安装 Playwright 浏览器: ``` npx playwright install --with-deps chrome ``` 在发布更改之前运行默认的本地质量门禁: ``` npm run check ``` ## Playground 构建包后,使用任何静态文件服务器托管仓库根目录,然后打开 `/playground/`。 ``` npm run build npm run serve ``` 然后访问 `http://localhost:4173/playground/`。 Playground 是一个三面板工作台,包含 HTML 输入、沙盒化预览,以及一个用于检查消毒器移除项、CSP 违规、外部请求和当前策略的检查器。它还包含示例 payload 以及用于 CSP 预设、外部协议和宿主后缀过滤的控件。你可以将 HTML 文件拖放到编辑器上,切换“已消毒的 HTML”视图以检查 pipeline 生成的确切文档,并使用“分享”将输入 + 预设编码为可共享的 URL。 ### 托管的 Playground `.github/workflows/pages.yml` 会在每次推送到 `main` 分支时将 Playground 部署到 GitHub Pages。该工作流构建库并组装一个镜像 Playground 相对导入的站点,因此无需进行任何代码更改。一次性设置:在仓库中,转到 **Settings → Pages → Source** 并选择 **GitHub Actions**。首次成功运行后,即可在 `https://preview-sandbox.github.io/html-preview-sandbox/playground/` 访问 Playground。 ## 状态 `v0.1.0` 已发布到 npm,并附带构建来源证明。这是最初的 TypeScript 实现,API 预计在 1.0 版本之前会进一步演进。
标签:CSP策略, HTML渲染, Web组件, XSS防御, 沙箱隔离, 特征检测, 自动化攻击