仓库里没有任何真实密钥。 wrangler.toml 里的两个变量都是空值。
| 放哪 | 内容 |
|---|---|
| Cloudflare 环境变量 | 只有 ADMIN_USER 与 ADMIN_PASS(面板账号) |
D1 数据库 settings 表 |
AI 接口地址与 Key、搜索 Key、QQ APPID 与 AppSecret 等 |
这样安排的好处:密钥不再散落在环境变量和文档里,改配置不用重新部署, 而且 D1 里的数据在 Cloudflare 侧是静态加密的。
wrangler.toml已设置keep_vars = true,部署不会清掉后台变量。 前提是[vars]里没有同名空值;如果临时加过迁移用的[vars],填完值后要删掉。ADMIN_USER/ADMIN_PASS最终应该用 Secret 类型,不要长期写进[vars]。
面板回读密钥时会打码成
sk-a****1234。 如果你只是改别的字段,把打码值原样提交回来,后端会自动保留原值,不会把真 Key 覆盖成星号。
node tools/scan-secrets.js # 或者 npm run check:secrets它会在仓库里搜:常见密钥前缀(sk-、ghp_、AKIA 等)、私钥块、
被填了值的 wrangler.toml 变量、*.dev.vars、疑似 QQ APPID/AppSecret 的数字串。
命中任何一条就退出码 1。
npm test 和 npm run test:all 都会先跑一遍这个检查。
- 用户名密码用定长比较,避免时序侧信道
- 同一 IP 连续失败 5 次锁定 15 分钟(计数在 D1 里,重启不丢)
- 会话是 HMAC 签名的 Cookie:
HttpOnly+Secure+SameSite=Strict+Path=/administrator - 改密码会让所有旧会话立刻失效(签名密钥由账号密码派生)
- 所有写接口都校验同源,拒绝跨站提交
- 面板路径固定是
/administrator,但没有登录就什么都看不到
- WebHook 模式的验签失败一律 401(fail-closed),不存在「验证不了就放行」
- WebSocket 模式根本不需要公网入口,别人扫不到
- 群消息默认只处理白名单里的群;要放开得在面板里显式打开「允许所有群聊」
- 部署的项目默认只吐静态文件;开启「预制后端 / 自定义后端」架构后,后端代码也只跑在自研 JS 解释器沙盒里:禁 eval、禁内网、超时即杀,
/api/…有每 IP 每分钟的频率限制,_backend.js永远不会被当作静态文件公开 - 文件路径里的
..、绝对路径、非法字符都会被拒绝
| 情况 | 处理 |
|---|---|
| 面板密码可能泄露 | 在 Cloudflare 后台改 ADMIN_PASS,旧会话立即全部失效 |
| AI Key 泄露 | 去上游后台吊销并换新,在面板里重新填 |
| AppSecret 泄露 | 去 QQ 机器人管理端重置,在面板里重新填 |
| 有人狂刷部署页面 | 面板里缩短部署时长、减少同时项目数;或直接删掉那个项目 |
| 日志里看到可疑登录 | 搜「登录失败」,必要时改密码 |
- 不做用户系统,只有你一个管理员账号
- 不收集访问者隐私,部署页面只统计次数,不记录 IP 与 UA
- 不把对话内容写进日志正文以外的地方(日志本身可在面板里随时清空)
- 所有响应都带:
Strict-Transport-Security、X-Content-Type-Options: nosniff、Referrer-Policy: strict-origin-when-cross-origin、Permissions-Policy: camera=(self), microphone=(self), geolocation=(self) - 面板与错误页:严格 CSP(
default-src 'none'),禁止一切外部资源 - 部署页:宽松 CSP(允许内联脚本/样式与 https 资源),并带
X-Frame-Options: SAMEORIGIN - 提交前可以再跑一次静态自检:
npm run audit它会检查所有 JS 的语法、相对 import 是否能解析、package.json 脚本引用的文件是否存在、
wrangler.toml 的 main 是否存在、Markdown 相对链接是否失效、关键文档是否齐全。