Skip to content

Security: bio-apple/ai

Security

docs/SECURITY.md

安全规范

本项目为纯前端静态站点(GitHub Pages),无服务端密钥托管。以下规则适用于所有贡献者与自动化任务。

1. 禁止硬编码 API Key

禁止将 OpenAI、Anthropic、DeepSeek、Google Gemini 等 LLM 服务商的 API_KEY 硬编码在源码、配置或 JSON 中并提交至 GitHub。

密钥一旦进入公开仓库,通常会在数秒内被全网爬虫扫描并盗刷。

CI 会在每次构建时扫描仓库,拦截常见密钥模式(见 scripts/validate_ci.py → validate_no_secrets)。

2. 本地开发配置

本地开发请在仓库根目录使用 .env.local:

cp .env.local.example .env.local
# 编辑 .env.local,填入本地专用变量
  • .env.local 已写入 .gitignore,不得提交。
  • npm run build 的 prebuild 阶段会自动加载 .env.local(见 scripts/load-env-local.mjs)。
  • Python 抓取脚本读取 os.environ;可在 shell 中 set -a && source .env.local && set +a 后再运行。

允许的本地 / CI 变量(非 LLM 密钥)

变量 用途
GA_MEASUREMENT_ID / PUBLIC_GA_MEASUREMENT_ID Google Analytics
CLARITY_PROJECT_ID / PUBLIC_CLARITY_PROJECT_ID Microsoft Clarity
UMAMI_* / PUBLIC_UMAMI_* Umami 统计
CLOUDFLARE_BEACON_TOKEN / PUBLIC_CLOUDFLARE_BEACON_TOKEN Cloudflare Web Analytics
GITHUB_TOKEN / GH_TOKEN 本地抓取脚本提高 GitHub API 限额
YOUTUBE_API_KEY / YOUTUBE_DATA_API_V3 / GOOGLE_API_KEY AI 视频日更:YouTube Data API v3 详情
VIDEO_SYNC_API_URL 本地构建:Cloudflare Worker URL(视频云端同步)
VIDEO_SYNC_SHARED_KEY 本地构建:共享 sync 码(默认 bioai-videos)
YTDLP_COOKIES_FILE 本地可选:yt-dlp Netscape cookies 文件路径
YTDLP_COOKIES_B64(仅 CI Secret) 可选:base64 编码的 cookies,供 Actions 写入临时文件

生产 CI 通过 GitHub Actions Secrets 注入上述构建变量,不要写入仓库。

3. 用户 API Key(浏览器端)

若功能需要用户自行填写 API Key:

  1. 仅保存在用户浏览器 localStorage 或 sessionStorage。
  2. 所有 LLM 请求必须由客户端直连对应服务商官方 API。
  3. 禁止经任何第三方不安全通道中转(包括自建无鉴权代理、公开 CORS 代理等)。
  4. 不得在构建产物、analytics-config.json 或任何静态 JSON 中写入用户或开发者密钥。

当前站点:localStorage / sessionStorage 用于主题、视频收藏、bioai.flywheel 行为日志等非密钥偏好(见 ux.js、videos.js、recommend.js)。

4. 站内搜索与本地 API

  • 生产环境:全站 / 站内检索使用客户端 search-index.json + Fuse.js(lib/search.js、knowledge.js)。面板文案是「在本站搜索」,不调用外部 LLM。
  • 本地可选:./start.sh 启动 FastAPI,/api/ask 为站内 BM25/Fuse 检索,不调用外部 LLM,也不承载用户密钥。
  • GitHub Pages 不部署 /api/* 路由。

5. 外链与 GitHub 探测(link-guard)

lib/link-guard.js(Layout 默认加载):

  • 外链自动补齐 rel="noopener noreferrer"
  • 图片加载失败时替换为本地 SVG 占位
  • 点击疑似 GitHub 仓库链接前,用 https://api.github.com 探测;仓库 404 时弹窗(复制链接 / 仍要打开 / 关闭)

因此 CSP connect-src 必须包含 https://api.github.com(见 config/csp.json)。探测失败时不阻断打开。

6. 误提交密钥

  1. 立即在对应服务商控制台轮换 / 吊销密钥。
  2. 从 Git 中清除该提交,并假定密钥已泄露,检查账单与用量。

7. Content-Security-Policy

站点通过 HTTP 响应头限制浏览器可加载的资源来源。

层级 文件 说明
主策略 config/csp.json → _headers Cloudflare 边缘注入;prebuild 自动同步
兜底 src/components/SecurityMeta.astro GitHub Pages 无自定义头时的 <meta> CSP

当前指令包括:

  • script-src-attr 'none' — 禁止内联事件处理器
  • frame-src 'none' / frame-ancestors 'none' — 禁止被嵌入 iframe
  • worker-src 'self' — 仅同域 Service Worker
  • object-src 'none' — 禁止插件
  • style-src-attr 'unsafe-inline' — 允许模板中的 style= 属性
  • script-src 含 'unsafe-inline' — ThemeBoot.astro 等首屏内联脚本

修改 CSP 时只编辑 config/csp.json,然后 node scripts/csp-policy.mjs 或 npm run build 同步 _headers。

connect-src 相关来源:

  • https://api.github.com — GitHub 仓库存活探测
  • https://*.workers.dev + 构建时注入的 Worker origin — Cloudflare 视频 KV 与 /meta(单层 * 不匹配 xxx.account.workers.dev,见 scripts/csp-policy.mjs)
  • https://noembed.com · https://api.microlink.io — 视频 oEmbed / 页面封面

8. CI 密钥扫描

npm run scan:secrets   # validate_ci.py secrets

相关文件

  • .gitignore — 忽略 .env.local
  • .env.local.example — 本地变量模板(含 VIDEO_SYNC_*)
  • config/csp.json — CSP 单一事实来源
  • lib/link-guard.js — 外链 / 图片 / GitHub 404 兜底
  • scripts/validate_ci.py — CI 密钥扫描与产物校验
  • _headers — Cloudflare 安全响应头(含 CSP)与静态资源缓存
  • FRONTEND.md — 前端能力(含 link-guard)
  • DEVELOPER.md — 开发速查

There aren't any published security advisories