安全基线
启动环境校验、安全响应头、错误边界与 API 错误处理的默认防护。
MuseMVP 内置了一组开箱即用的安全基线:服务启动时校验环境变量、全站下发安全响应头、分层错误边界兜底、API 统一错误处理,以及针对计费 webhook 与邮件链路的加固。这些防护默认启用,无需额外配置。
设计原则
生产环境的配置错误应在启动时快速失败(fail fast),而不是在请求中途暴露为难以排查的运行时错误;非致命问题降级为警告日志,不阻塞部署。
启动环境校验
服务端环境变量由 src/lib/env.ts 中的 Zod schema 校验,经 src/instrumentation.ts 的 register() 在服务启动时调用一次。
- 致命错误:生产运行时缺少
BETTER_AUTH_SECRET会直接抛错终止启动。next build与本地 dev 不受影响,仅记录错误日志。 - 非致命警告:以下配置问题只输出警告日志,不阻塞启动。
| 场景 | 警告条件 | 影响 |
|---|---|---|
| 计费网关 | 已配置网关 API Key 但缺少对应 webhook secret | 生产环境 webhook 会被拒绝 |
| 数据库连接 | DATABASE_CONNECTION_STRATEGY=database_url_first 但未设置 DATABASE_URL | 数据库连接失败 |
| 邮件服务 | MAIL_PROVIDER=resend 但未设置 RESEND_API_KEY | 事务邮件发送失败 |
安全响应头
next.config.mjs 的 headers() 对全部路由(/:path*)下发以下安全响应头:
| 响应头 | 值 | 作用 |
|---|---|---|
Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | 强制 HTTPS |
X-Frame-Options | SAMEORIGIN | 防止跨站 iframe 嵌入(点击劫持) |
X-Content-Type-Options | nosniff | 禁止 MIME 类型嗅探 |
Referrer-Policy | strict-origin-when-cross-origin | 限制 Referrer 泄露 |
Permissions-Policy | camera=(), microphone=(), geolocation=(), browsing-topics=() | 默认禁用敏感浏览器能力 |
关于 CSP
Content-Security-Policy 暂未包含在内:Next.js 内联脚本需要按请求生成 nonce,且需为第三方脚本(统计、Turnstile、Google One Tap)逐一放行,计划作为独立事项跟进。
错误边界
App Router 采用分层错误边界,未捕获异常不会导致白屏:
全局兜底
src/app/global-error.tsx — 最后一道防线,替换根 layout 自行渲染 html/body,使用内联样式与非本地化文案。
落地页边界
src/app/(landing-page)/[locale]/error.tsx — 捕获营销页段内异常,渲染共享回退组件。
应用页边界
src/app/(saas-page)/app/error.tsx — 捕获 SaaS 应用段内异常,渲染共享回退组件。
两个分段边界共享 ErrorState 回退组件,提供重试与回首页两个操作,文案在 i18n 的 errors 命名空间中维护(en/zh)。
API 错误处理
Hono API(src/backend/api/app.ts)在入口层统一处理错误与请求体大小:
统一错误结构:app.onError 捕获所有逃逸出 handler 的异常,记录日志后返回统一 JSON 错误结构({ ok: false, error: "Internal Server Error" }),不向客户端泄露内部细节。
HTTPException 透传:路由主动抛出的 HTTPException 保留其自身响应,不被覆盖。
请求体限制:hono/body-limit 限制请求体最大 1MB,超限返回 413。文件上传走 presigned URL 直传对象存储,不受此限制影响。
计费与邮件加固
- Webhook 签名强制校验:生产环境下 Creem 与 Stripe 的 webhook 强制要求配置 webhook secret,缺失时直接抛错拒绝处理(与 Dodo 行为一致)。
- Newsletter 退订 token:退订链接 token 采用 HMAC-SHA256 签名并使用常量时间比较验证,token 不可伪造,同时修复了此前的反射型 XSS 问题。
- Auth 邮件真实报错:OTP、magic link、密码重置邮件发送失败时向客户端返回真实错误,而不是静默显示成功导致用户永远收不到邮件。