安全
00 / 00

网站安全

用新手能理解的方式,判断什么时候需要 Cloudflare、限流、人机验证、上传限制和密钥保护

为什么要关心安全

早期产品的安全问题通常不是电影里的“黑客入侵”。更常见的是:你的短信验证码被人疯狂调用,AI 额度一夜用完,反馈表单塞满垃圾内容,上传入口被当成免费网盘,或者支付成功通知被伪造。

这些问题的共同点是:攻击者不一定要真的“攻破系统”,只要能反复调用某个入口,就可能让你花钱、让服务变慢,或者让正常用户没法使用。

安全不放进“部署与运维”下面。部署与运维关注上线、域名、日志、健康检查和统计;安全会横跨登录、支付、AI、上传、权限和管理后台,所以作为独立章节保留。上线检查会从部署指南链接到这里,但具体安全策略在本章节维护。

先按这几个问题判断

你遇到的问题优先措施说明
网站请求突然暴涨,页面变慢Cloudflare 代理、WAF、边缘限流先在访问到达服务器前挡掉明显异常流量
短信验证码、邮件验证码被刷接口限流,必要时开启人机验证这是最容易直接产生账单的入口
登录失败次数异常增多登录限流、2FA、人机验证这是常见的撞库和批量试密码
AI 生成、搜索、上传被频繁调用单独给这些高成本动作限流高成本动作不要只靠全站统一限制
上传文件越来越多、越来越大上传大小、类型、次数限制防止存储费用失控,也避免违规文件
担心 API key 泄露密钥只放环境变量,提交前做检查泄露后要第一时间轮换,而不是只删代码

安全措施不是越多越好。我的建议是:默认先把 Cloudflare 代理、基础限流、上传边界和密钥管理做好;Turnstile 这类会影响体验的验证,只放在高风险动作或攻击期使用。

安全头和 CSP

01MVP 模板默认设置了一组浏览器安全头,包括 Content-Security-PolicyX-Frame-OptionsX-Content-Type-OptionsReferrer-PolicyPermissions-Policy

CSP 的作用不是让网站“跑得起来”,而是限制浏览器可以从哪里加载脚本、图片、字体、接口请求和表单提交。MDN 对 Content-Security-Policy 的解释是:它允许网站控制当前页面能加载哪些资源,并帮助防御跨站脚本攻击。Next.js 官方文档也把 CSP 作为防护 XSS、clickjacking 和代码注入攻击的手段。

对初创小团队来说,CSP 更适合在产品域名、第三方统计、验证码、支付、客服、错误上报这些来源稳定后再开启。它的收益是真实的,但维护成本也是真实的:只要忘记把新域名加入 allowlist,浏览器就可能直接拦掉登录、注册、统计、验证码或错误上报请求,用户看到的通常只是 Failed to fetch

你只需要记住两点:

  • 默认安全头不要删。它们是浏览器层面的基础防护。
  • 接入新的第三方脚本时,比如 GA、Umami、支付组件、客服插件或 Sentry/PostHog,如果浏览器控制台出现 CSP 报错,把可信域名加进 products/01mvp/apps/web/security-headers.mjs 的 allowlist。

模板的 CSP 源配置在 products/01mvp/apps/web/security-headers.mjs。这里会生成 Cloudflare 静态部署用的 products/01mvp/apps/web/public/_headers,也会被运行时安全头复用。改完 allowlist 后运行:

vpr @01mvp/web#security:headers

不要直接手改 public/_headers,否则下次构建或安全头生成脚本会把它覆盖。

Cloudflare Web Analytics 是一个典型例子。Cloudflare 官方文档说明,Web Analytics beacon 会从 https://static.cloudflareinsights.com/beacon.min.js 加载;如果网站设置了 CSP,就可能需要更新 CSP 才能加载这个脚本。所以 01MVP 模板默认在 script-src 里放行 https://static.cloudflareinsights.com,否则小橙云自动注入成功了,浏览器也可能把脚本拦掉。

Cloudflare Turnstile 也是模板内置的可选能力。Cloudflare Turnstile 的 CSP 文档要求放行 https://challenges.cloudflare.com 的脚本和 iframe,所以模板默认把它放进 script-srcframe-srcconnect-src

GitHub、Google、微信登录不需要因为 OAuth 跳转额外加入 CSP allowlist。它们通常是浏览器顶层跳转到第三方授权页,不是从你的页面加载第三方脚本或 iframe。头像图片也不需要额外加域名,因为模板的 img-src 已允许 HTTPS 图片。

服务端请求也不需要加入浏览器 CSP。比如后端在 Hono、oRPC procedure、server-only module 或后台任务里请求 OpenAI-compatible API、短信服务、支付服务、对象存储,这些请求由服务器发出,不经过用户浏览器的 CSP。只有浏览器页面自己发出的请求才会被 connect-src 限制,比如 analytics beacon、Sentry browser SDK 上报、PostHog 浏览器采集、前端直接 fetch() 第三方接口。

排查 CSP 报错时,看浏览器 Console 里的三件事:被拦的是 script-srcconnect-src 还是 frame-src;被拦的完整域名是什么;这个域名是否来自你主动接入的可信服务。确认后再加 allowlist。

如果开启 CSP 后,第三方统计、验证码、客服脚本或登录请求一直被拦住,可以先关闭 CSP 排查。关闭需要同时处理静态头和运行时头:

  • products/01mvp/apps/web/security-headers.mjs:从 BASE_SECURITY_HEADERS 中移除 ["Content-Security-Policy", CONTENT_SECURITY_POLICY],然后运行 vpr @01mvp/web#security:headers 重新生成 public/_headers
  • products/01mvp/apps/web/src/server/security-headers.ts:从 getSecurityHeaders() 返回值中移除 Content-Security-Policy 这一项。

排查完后,再按 Console 里被拦的可信域名补 allowlist,然后决定是否重新打开 CSP。

常见风险

安全能力分层

层级保护什么典型措施
访问入口网站别被流量打垮Cloudflare 代理、WAF、边缘限流
付费动作短信、AI、邮件、搜索、上传别被刷应用限流、登录态、配额
人机判断批量脚本不要轻易通过Local PoW、Cloudflare Turnstile
数据和文件文件别无限上传,密钥别泄露上传限制、环境变量、安全检查
账号权限用户和管理员别越权路由保护、权限模型、2FA、管理员审计

账号和权限

下面这些页面更偏开发和后台管理,但仍然属于安全体系:

相关资源

这篇文档有问题?