Files
tootaio.com/docs/20251107/security-audit.md
xiaomai cc0cb01d28 fix(security): apply security hardening recommendations from audit
This commit implements several security enhancements based on the findings of a new security audit report, which has also been added to the documentation.

- **Security Headers:** Adds a strict Content-Security-Policy (CSP) and other security headers (X-Content-Type-Options, Referrer-Policy) via Nuxt route rules.
- **Production Hardening:** Disables Nuxt DevTools in production environments to reduce the attack surface.
- **Mixed Content:** All image assets are now loaded over HTTPS to resolve mixed content issues.
- **Tabnabbing:** Secures `window.open` calls by adding `noopener,noreferrer`.
- **Configuration:** Updates `.gitignore` to ignore all `.env.*` files.
- **Docs:** Adds the full security audit report for reference.
- **Build:** Corrects a case-sensitive import path to ensure cross-platform build compatibility.
2025-11-07 11:15:02 +08:00

6.7 KiB
Raw Blame History

title, description, lastUpdated
title description lastUpdated
安全审计报告Tootaio Studio 网站) 开源发布前的安全评估与加固建议与清单 2025-11-07

概览Summary

  • 架构为 Nuxt 4 + @nuxt/content 的前端站点,无自建服务端 API/上传功能,攻击面小。若开源,整体安全风险低。
  • 主要关注点:外部资源使用 HTTP、窗口打开的 opener 风险、生产环境 DevTools 启用、缺少统一安全响应头、依赖冗余与未来内容来源治理。

审计范围

  • 配置与依赖:nuxt.config.tspackage.json.env*.gitignore
  • 前端页面与可执行逻辑:app/ 下的页面、布局、可组合函数composables
  • 内容与多语言:content/**.ymli18n/**.json
  • 文档与脚本:docs/ 内建议信息。

结论与优先级

  • 风险等级:低-中LowMedium。不存在明显的密钥泄露或远程代码执行面。
  • 高价值、低成本修复项(建议开源前完成):
    1. 将所有外部资源统一为 HTTPS。
    2. 生产环境禁用 DevTools。
    3. window.open 显式使用 noopener,noreferrer
    4. 为外链/图片增加基础协议白名单校验http/https
    5. 通过网关或 Nitro routeRules 添加基础安全响应头与静态资源缓存策略。
    6. 精简未使用依赖(如未使用 better-sqlite3)。

关键发现与证据Evidence

  • 公开运行时配置(非敏感):

    • nuxt.config.ts:22 暴露 runtimeConfig.public.whatsappNumber(按设计公开,无敏感性)。
  • DevTools 在生产可能启用:

    • nuxt.config.ts:14 devtools: { enabled: true },建议生产禁用。
  • 外链/图片使用了 HTTP混合内容与篡改风险

    • app/pages/index.vue:83-92 背景图 http://img.tootaio.com/...
    • content/en-US/index.yml:25,29content/zh-CN/index.yml:31,35 项目图片使用 http://
  • 外链打开策略:

    • app/pages/index.vue:37-38 使用 target="_blank" 已含 rel="noopener",建议补充 noreferrer
    • app/composables/WhatsAppMsgSender.ts:11window.open 未显式 noopener,noreferrer
  • 统一安全头缺失:

    • 未在 nuxt.config.ts 配置 routeRules 的安全头(可在网关/Nginx 层或 Nitro 层补充)。
  • 依赖冗余:

    • package.json:19 引入了 better-sqlite3,当前项目未使用,建议移除以降低供应链与构建复杂度。
  • 非安全但会影响构建的细节:

    • content.config.ts:2 大小写引用与实际文件名不一致Linux 下可能报错):应从 ./app/schemas/PricingPlanSchema 调整为 ./app/schemas/pricingPlanSchema
  • 环境文件治理:

    • .env 已被 .gitignore 忽略(.gitignore:22),且内容仅有公开号码(.env:1)。建议继续保持从未提交到历史。

修复与加固建议Actionable

开源前必须High Priority

  • 统一使用 HTTPS 资源

    • http://img.tootaio.com/... 统一替换为 https://img.tootaio.com/...
    • 建议将资源基址抽离到 runtimeConfig.public.assetBase 并集中管理,减少散落硬编码。
  • 生产禁用 DevTools

    • devtools 改为:devtools: { enabled: process.env.NODE_ENV !== 'production' }
  • window.open 加固

    • 修改为:window.open(url, '_blank', 'noopener,noreferrer') 或在新窗口上设置 opener = null
  • 外链与图片的协议白名单

    • 在渲染外链/图片前校验 URL 协议,只允许 http:https:,避免 javascript:data: 等危险 scheme。
  • 安全响应头(建议由网关/Nginx 配置,或用 Nitro routeRules

    • 最小集:
      • Content-Security-Policy(仅放行必要域名,样例见下)。
      • X-Content-Type-Options: nosniff
      • Referrer-Policy: strict-origin-when-cross-origin
      • Permissions-Policy(按需收紧)
    • 静态资源缓存:/_nuxt/** 设置 Cache-Control: public, max-age=31536000, immutable

建议完成Medium Priority

  • 依赖精简

    • 若未用到 better-sqlite3,从 package.json 移除并更新锁文件。
  • .gitignore 更严格忽略 env 变体

    • 将当前注释掉的 .env.* 忽略规则启用,并保留示例白名单:
      • 忽略:.env.env.*
      • 白名单:!.env.sample
  • 文件名大小写一致性

    • content.config.ts 引用改为实际文件名大小写以避免跨平台问题。

可选增强Nice-to-have

  • 在 CI 中启用:

    • pnpm install --frozen-lockfile
    • 依赖与漏洞审计Dependabot / pnpm audit --prod
    • Secrets 扫描(gitleaks/trufflehog
  • HSTS 与全站 HTTPS

    • 前置网关开启 HSTS并确保所有外链与资源均可通过 HTTPS 访问。

附录:建议配置片段

1) Nitro routeRules示例

// nuxt.config.ts
export default defineNuxtConfig({
  // ...
  routeRules: {
    '/**': {
      headers: {
        'Content-Security-Policy': [
          "default-src 'self'",
          "script-src 'self'",
          "style-src 'self' 'unsafe-inline'",
          "img-src 'self' https://img.tootaio.com data:",
          "connect-src 'self'",
          "frame-ancestors 'self'",
          'upgrade-insecure-requests',
        ].join('; '),
        'X-Content-Type-Options': 'nosniff',
        'Referrer-Policy': 'strict-origin-when-cross-origin',
      },
    },
    '/_nuxt/**': {
      headers: { 'cache-control': 'public, max-age=31536000, immutable' },
    },
  },
})

请按实际依赖域名精简 CSP特别是 img-srcconnect-src

2) window.open 安全用法(示例)

const win = window.open(url, '_blank', 'noopener,noreferrer')
// 或者:
const win = window.open(url, '_blank')
if (win) win.opener = null

3) 外链协议白名单(示意)

function isSafeHttpUrl(href: string) {
  try {
    const u = new URL(href)
    return u.protocol === 'http:' || u.protocol === 'https:'
  } catch {
    return false
  }
}

// 使用时:
// <UButton v-if="item.demoLink && isSafeHttpUrl(item.demoLink)" :href="item.demoLink" ... />

4) DevTools 生产禁用

export default defineNuxtConfig({
  devtools: { enabled: process.env.NODE_ENV !== 'production' },
})

5) .gitignore 建议

# Local env files
.env
.env.*
!.env.sample

附注Non-security 但建议修复)

  • content.config.ts:2 的大小写引用问题:应改为 ./app/schemas/pricingPlanSchema(与实际文件名一致),避免在大小写敏感的文件系统上构建失败。

下一步

  • 如需我可以基于本报告直接提交最小化补丁HTTPS 资源替换、devtools 切换、window.open 加固、routeRules 安全头、.gitignore 调整、文件名大小写修复),并附上验证与回退说明。