如果你用 Claude 或 Cursor 快速开发了一个应用,准备交给付费客户,先等等。AI 生成的代码存在可预测的安全漏洞——暴露的 API 密钥、缺少输入验证、默认数据库权限允许任何用户查看其他用户的数据。这些不是边界情况。几乎每个首次 AI 生成的代码库都会出现这些问题。
本指南是上线前的安全检查清单。在任何真实用户接触你的应用之前,逐步按照它执行。它是针对最常见的快速开发堆栈(Next.js + Supabase + Vercel)编写的,但这些原则不受你使用的工具限制。
为什么 AI 生成的代码存在安全问题
AI 模型优化的是"能否正常工作?"而不是"是否安全?"当你告诉 Claude "给我构建一个带用户账户的任务管理器"时,它会生成创建用户、存储任务并显示它们的代码。但它可能不会自动做到的是:确保用户 A 看不到用户 B 的任务、验证输入字段不能接受恶意脚本、隐藏浏览器开发者工具中的 API 密钥,或添加速率限制来防止有人轰击你的端点。
这些不是 AI 的失败——它们是提示词中的空白。AI 构建的是你要求的东西。你可能没有要求安全性,因为你专注于功能。现在是时候回过头来添加它。
步骤 1:审计你的环境变量
这是快速开发应用中最常见且最危险的错误。检查你项目中的每个文件,查找硬编码的 API 密钥、数据库 URL 或机密。
要查找的内容:搜索你的代码库以查找以 sk-、eyJ、sbp_、supabase、postgres:// 开头的字符串,或任何看起来很长的随机字符串。特别检查这些文件:/app 或 /pages 目录中的任何文件、任何组件文件、你的 next.config.js 以及任何工具文件。
修复方法:将每个机密移到环境变量中。在 Next.js 中,只有以 NEXT_PUBLIC_ 为前缀的变量才会暴露给浏览器。你的数据库 URL、服务角色密钥和 API 机密永远不应该有这个前缀。
# .env.local(永远不要提交此文件)
SUPABASE_SERVICE_ROLE_KEY=your-secret-key
DATABASE_URL=postgres://...
# 这些可以安全地暴露给浏览器:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
验证:检查你的 .gitignore 文件包含 .env.local。如果你已经将机密提交到 Git,它们在历史记录中即使删除后仍然存在——立即轮换(重新生成)每个暴露的密钥。
步骤 2:在 Supabase 中启用行级安全
如果你使用 Supabase,这是最关键的单一步骤。默认情况下,Supabase 表没有访问限制——任何拥有你的 anon 密钥的人都可以读取和写入每个表中的每一行。这意味着用户 A 可以通过简单的 API 调用查看用户 B 的数据。
修复方法:在每个表上启用行级安全 (RLS),然后创建限制访问的策略。
转到你的 Supabase 仪表板 → 表编辑器 → 选择每个表 → 点击"RLS 已禁用"以启用它。然后添加策略:
对于用户应该只看到自己数据的典型应用,创建一个 SELECT 策略:auth.uid() = user_id。为 INSERT、UPDATE 和 DELETE 创建类似的策略。
测试它:以用户 A 身份登录,尝试通过 API 访问用户 B 的数据。如果你能看到,你的策略有问题。Supabase 有一个 SQL 编辑器,你可以直接测试策略。
常见 AI 错误:Claude 经常使用 service_role 密钥(绕过 RLS)生成 Supabase 查询,而不是使用具有适当 RLS 策略的 anon 密钥。检查你的客户端代码仅使用 anon 密钥。服务角色密钥应该只存在于服务器端代码(API 路由、服务器操作)中,永远不要暴露给浏览器。
步骤 3:正确添加身份验证
AI 生成的身份验证代码通常可以工作,但会采取快捷方式。检查这些具体问题:
会话管理:确保会话过期。检查你的身份验证设置包含合理的会话超时时间(Supabase 默认值通常没问题,但要验证)。确保登出实际上使会话失效,而不仅仅是清除本地 cookie。
密码要求:如果你有电子邮件/密码身份验证,强制要求最小密码长度(8+ 个字符)。Supabase 在你的项目设置 → 身份验证 → 密码要求中处理此问题。
受保护的路由:每个显示用户特定数据的页面都需要身份验证中间件。在 Next.js App Router 中,创建一个检查有效会话的中间件,并将未经身份验证的用户重定向到登录页面。不要仅依赖客户端检查——用户可以通过直接访问你的 API 来绕过这些检查。
电子邮件验证:在 Supabase 身份验证设置中启用电子邮件确认。这可防止用户使用虚假电子邮件地址创建账户,并增加了一个基本的账户有效性层。
从中获得价值?我们每周发布一篇关于 AI 工具、工作流和实用指南的深度文章。加入抢先获得的读者 →
步骤 4:验证所有输入
AI 生成的表单通常具有基本验证(必填字段、电子邮件格式),但很少防止恶意输入。
要添加的内容:
在每个 API 端点上进行服务器端验证。永远不要仅依赖客户端验证——它可以通过直接向你的 API 发送请求来绕过。使用诸如 Zod(针对 TypeScript)之类的验证库为你的应用接受的每个数据片段定义架构。
在任何在浏览器中呈现的用户生成内容中清理 HTML。如果你的应用有评论、描述或任何在浏览器中呈现的文本字段,请使用诸如 DOMPurify 之类的库来删除危险脚本。没有这个,有人可以注入 JavaScript 来窃取其他用户的会话(跨站脚本 / XSS)。
如果你的应用接受文件上传,限制文件上传的大小和类型。AI 生成的上传处理程序通常没有限制,意味着有人可以上传 2GB 文件或可执行文件。添加大小限制(对于大多数应用来说 5MB 是合理的)并将文件类型限制为你实际需要的文件(图像、PDF 等)。
步骤 5:保护你的 API 路由
检查你的应用中的每个 API 路由或服务器操作是否存在这些问题:
每个端点上的身份验证。返回或修改用户数据的每个 API 路由应该先验证用户的会话。AI 经常生成接受来自任何人的请求的 API 路由。
超越身份验证的授权。即使确认用户已登录,也要验证他们是否被允许访问他们请求的特定资源。"用户 A 已登录"并不意味着"用户 A 可以编辑用户 B 的资料"。在每次数据访问时检查所有权。
速率限制。没有速率限制,有人可以每秒向你的 API 发送数千个请求,以抓取数据或压倒你的服务器。使用诸如 rate-limiter-flexible 之类的库添加基本速率限制,或在 Edge Functions 上使用 Vercel 的内置速率限制。
HTTP 方法。确保你的 API 路由仅响应它们应该响应的 HTTP 方法。处理 POST 请求的路由在没有明确设计的情况下不应该也响应 DELETE 请求。
步骤 6:检查你的部署配置
你的部署平台有 AI 不为你配置的安全设置。
Vercel 设置要检查:启用"部署保护"(需要身份验证才能查看预览部署——防止客户端意外共享暴露进行中工作的预览 URL)。设置支出限制以防止如果你的应用遭遇流量峰值时的意外费用。在 CORS 标头中配置你的允许域。
自定义域和 SSL:如果你要将此交付给客户端,请使用 HTTPS 设置他们的自定义域。Vercel 和 Netlify 会自动处理 SSL。永远不要在 .vercel.app 子域上交付客户端应用——它看起来不专业,客户端也无法轻松转移它。
标头:将安全标头添加到你的 next.config.js 或 vercel.json:X-Content-Type-Options: nosniff、X-Frame-Options: DENY(防止你的网站被嵌入在 iframe 中进行点击劫持)、Strict-Transport-Security(强制 HTTPS)。这些是一次性添加,可防止整个攻击类别。
步骤 7:运行最终安全扫描
在交付任何东西给客户端之前,运行这些免费检查:
npm audit:在你的项目目录中运行 npm audit。它会标记你的依赖项中的已知漏洞。修复严重和高风险问题。在可用的地方运行 npm audit fix 进行自动修复。
Lighthouse:在 Chrome 中打开你的部署站点,打开 DevTools,运行 Lighthouse 审计。检查"最佳实践"分数——它会捕捉常见的安全问题,如缺少 HTTPS、易受攻击的库和不安全的标头。
手动测试:以一个用户身份登录,尝试通过修改 URL 或 API 调用来访问另一个用户的数据。尝试提交空表单、超大输入和特殊字符(如编码的 XSS 有效负载)。如果这些中的任何一个有效,你有问题要解决。
上线前检查清单
打印这个并在上线前检查每一项:
- 所有机密都在环境变量中(没有硬编码密钥)
.env.local在.gitignore中(并且 Git 历史记录中没有机密)- Supabase RLS 在每个表上启用
- RLS 策略已测试(用户 A 看不到用户 B 的数据)
- 客户端代码仅使用 anon 密钥(服务角色密钥仅在服务器端)
- 每个 API 路由上的身份验证
- 数据访问上的授权检查(所有权验证)
- 每个表单上的输入验证(服务器端,不仅仅是客户端)
- 文件上传限制(大小和类型)(如适用)
- API 端点上的速率限制
- 安全标头已配置
- 已运行
npm audit并修复了关键问题 - 自定义域配置有 SSL
- 预览部署已受保护
- 手动跨用户数据访问测试已通过
底线
保护快速开发的应用不是关于成为安全专家。它是关于运行一个检查清单,该清单捕捉 AI 留下的可预测空白。上述步骤需要 2-4 小时,并可防止最常见的漏洞。对于面向客户端的应用,这不是可选的——这是专业工作和责任之间的区别。
如果你正在构建你的第一个快速开发应用,请从我们的快速开发完整指南开始。如果你想改进你与 Claude 或 Cursor 一起使用的提示,请尝试我们的免费提示优化器。关于最佳编码工具的细目,请参阅Claude Code vs Codex。
这是我们每周做的事情。关于 AI 工具、工作流和诚实观点的一篇深度文章——无炒作,无填充。加入我们 →
披露:本文中的某些链接是关联链接。我们只推荐我们亲自测试并定期使用的工具。请参阅我们的完整披露政策。