静态站点的内容保护是个尴尬的命题。
GitHub Pages、对象存储、CDN——纯静态托管便宜到几乎免费,可它们没有服务端。「想给某个页面加密码、只让特定人看」这个再普通不过的需求,通常意味着得引入后端:一份鉴权服务、一个登录态、可能还有数据库。为了一个密码框,把无状态的静态站点拖回有状态架构,不划算。
StaticShield 换了个思路:把加密下沉到产物本身。用密码把 HTML 加密成一份「自解密页面」,密文与解密逻辑都内嵌在同一个 .html 里;部署照旧是纯静态,访客输入密码后由浏览器端 WebCrypto 实时还原。全程零后端。
主打:Web GUI 加密(本地后端)
日常加密走图形界面。--gui 会拉起一个仅绑定 127.0.0.1 的本地服务并打开浏览器:
1 | node encrypt.js --gui |
架构上是「本地 Node 后端 + 浏览器前端」,这么设计有一个关键原因:打包多文件网页需要文件系统访问,而浏览器在 file:// 下出于安全拿不到相对路径资源。所以加密放在本地 Node 端做(能读目录、能 bundle),前端只负责交互与上传——文件不离开本机。
两种模式:
- 单文件:选一个 HTML → 加密下载。
- 整个文件夹:用
webkitdirectory选网页根目录(index.html+css/+js/+ 图片),后端先内联打包再加密,等效于 CLI 的--bundle。
底层是 Node http + 异步 WebCrypto(跑在 libuv 线程池),多个标签、多台设备同时访问可并行加密,互不阻塞;每请求独立临时目录、无全局可变状态。
本地服务的安全细节也做了:仅监听 127.0.0.1、Host 头校验(防 DNS rebinding 跨域读取响应)、Content-Type 校验、上传路径沙箱(防 ../../ 逃逸)、请求体大小上限与不活动超时。
加密管线:AES-256 + PBKDF2 + HMAC
不是 base64 藏一下,是正经的对称加密组合(Encrypt-then-MAC):
- 密钥派生:
PBKDF2(password, salt, 1,000,000)→ 64 字节,前 32 字节作encKey、后 32 字节作macKey,加密与签名密钥隔离。 - 加密:
AES-256-CBC(随机 IV)加密明文 HTML。 - 签名:
HMAC-SHA256(macKey, AAD ‖ iv ‖ salt ‖ ct),其中 AAD 把cipher / kdf / iter等影响派生的元数据一并纳入——篡改迭代次数降级、或改成天文数字耗尽 CPU 的攻击,会直接验签失败。 - 解密:先验签、后解密。验签不过即统一报错,不区分「密码错」与「文件损坏」,既避免信息泄露,也消除了 padding oracle 攻击面。
加密端(CLI / GUI 后端)与解密端(浏览器)共用同一份 crypto-core.js——基于 globalThis.crypto.subtle 的同构模块,Node 18+ 与浏览器跑同一份代码,产物格式一致、单点维护。
多文件网页:内联打包
--bundle(或 GUI「整个文件夹」)做的事,是把整站压成单个自包含 HTML 再加密:
<link rel=stylesheet>→<style>,递归内联 css 内@import与url()<script src>→ 内联<script>,严格保持原加载顺序(依赖序不能乱)<img / audio / video>.src、poster、srcset、favicon →data:URIhttp(s)/ CDN 绝对 URL 原样保留;相对路径沙箱约束在项目目录树内,防路径遍历
打包后仍是单 HTML,解密端无需任何改动。
CLI:给开发者的选项
GUI 适合一次性操作;需要脚本化、批量、或接进 CI/CD 时,CLI 更顺手:
1 | # 打包整站 + 生成 16 位强密码 + 指定输出目录 |
参数覆盖:--bundle(打包)、--gen-pwd [n](CSPRNG 生成强密码,拒绝采样消除模偏差)、--share(生成 #pwd= 自动解密链接)、--sha512、--remember <days>、--hint、--logo、-d 输出目录。-p 缺省则交互式提示输入(不回显,且正确处理 UTF-8 多字节密码的退格)。
部署:纯静态,随便放
产物是单个 .html,任何静态托管都行——GitHub Pages、Vercel / Netlify、OSS / COS / S3、Nginx,甚至直接发文件双击打开。无需运行时、无需数据库。唯一要注意:WebCrypto 仅在安全上下文可用(https://、localhost、file://),纯 HTTP 部署会提示需 HTTPS。
安全边界得说清楚:浏览器端解密意味着密文会下发到客户端,StaticShield 属「门禁式」访问控制(防直接查看 / 抓取 / 爬虫),不构成对资深逆向者的绝对防护。但作为挡住绝大多数随意访问的一道门,成本几乎为零——零后端、零运行时依赖、一个文件部署。
适合付费内容预览、内部文档分享、临时私密页面。