安全不是装一个插件。是浏览器帮你挡第一刀。
昨天 Day 63 讲速度:LCP、INP、CLS。
今天讲另一半——用户敢不敢把数据交给你。
很多工具站上线时只顾「能用、能收录、能变现」,安全头(Security Headers)几乎全空:
Content-Security-PolicyX-Frame-Options / frame-ancestorsStrict-Transport-SecurityReferrer-Policy、Permissions-Policy结果呢?
上线一周,安全扫描一跑:一屏红。 不是黑客盯上了你,是默认配置等于开着门睡觉。
冰山线:
你以为在做性能和 SEO,其实还在决定:浏览器愿不愿意替你守门。
安全头 | 一句话人话 | 工具站优先级 | 先怎么做 |
|---|---|---|---|
HTTPS + HSTS | 全程加密,下次强制 https | P0 | 证书 + Strict-Transport-Security |
CSP | 只准加载你允许的脚本/样式 | P0 | 先 Report-Only,再收紧 |
frame-ancestors / XFO | 别人不能把你嵌进钓鱼页 | P0 | DENY 或只放自己域名 |
X-Content-Type-Options | 别让浏览器乱猜文件类型 | P1 | 固定 nosniff |
Referrer-Policy | 外链时少带敏感路径 | P1 | strict-origin-when-cross-origin |
Permissions-Policy | 关掉摄像头/麦克风等默认权限 | P1 | 按需白名单 |
Day 64 北极星:
出海工具站的安全第一周,不是「上 WAF 装杀软」,是:让 6 个响应头先站岗。
证据说明:下列语法与意图以 MDN Web Docs / OWASP 安全头清单 的公开说明为准(✅);具体分值、扫描工具报错文案因厂商不同会变(⚠️)。「加了头就永不被黑」❌ 不做这种保证——安全是分层的,头只是浏览器侧的第一层。
游戏攻略站、格式转换站、在线计算器,有三个共性:
一人团队更残酷:
所以 Day 64 不写「零信任架构白皮书」,只写 清单:测什么、加什么、怎么不把自己锁死。
HTTPS 是底线:证书过期、混用 http 资源(mixed content),现代浏览器会直接警告。
HSTS(Strict-Transport-Security) 更进一步:告诉浏览器——「以后来我这站,只用 https,别试 http」。
常见写法(示例,按你域名与是否含子域调整):
Strict-Transport-Security: max-age=31536000; includeSubDomains要点:
max-ageincludeSubDomains工具站踩坑:CDN / 自定义域名只配了 apex,www 还在跳 http → HSTS 一开,排错更麻烦。先统一跳转,再开 HSTS。
Content-Security-Policy(CSP) 是浏览器侧的「资源白名单」。
它能显著削弱:
MDN 公开说明:CSP 通过 HTTP 响应头(或 meta,但头更完整)告诉浏览器允许加载哪些脚本、样式、图片、连接等(✅)。
工具站推荐节奏(别一步封死):
阶段 | 做法 | 目的 |
|---|---|---|
第 1 天 | Content-Security-Policy-Report-Only | 只报告,不拦截,看会炸什么 |
第 3–7 天 | 根据报告收紧 script-src / style-src | 干掉内联乱用、未知域名 |
稳定后 | 正式 Content-Security-Policy | 真正拦截 |
起步示例(仅示意,必须按你站实际域名改):
Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; script-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'人话版注意:
'unsafe-inline' 是妥协,不是终点;能上 nonce/hash 更好扫描器常报「无 CSP」。你要回的不是「我装了安全插件」,而是:头在不在、策略是否可执行。
有人把你的登录页、支付页、工具结果页 嵌进恶意站点的 iframe,做成钓鱼界面——用户以为在用你,其实在输给别人。
两套机制:
头 | 状态 | 常见值 |
|---|---|---|
X-Frame-Options | 老但还常见 | DENY / SAMEORIGIN |
CSP frame-ancestors | 更现代、更细 | 'none' / 'self' / 指定域名 |
工具站默认建议:
frame-ancestors 'none' 或 X-Frame-Options: DENYSAMEORIGIN / 'self'公开文档里,限制嵌入是点击劫持防护的标准路径之一(✅ MDN CSP / 点击劫持相关说明)。
浏览器有时会「聪明地」根据内容猜 MIME 类型。 攻击者可能上传看起来像图片的文件,实际被当脚本执行。
固定:
X-Content-Type-Options: nosniff成本几乎为零,扫描器几乎必查。工具站 上传/预览 场景尤其要开。
用户从你站点到外链,Referer 可能带上:
常见稳妥值:
Referrer-Policy: strict-origin-when-cross-origin含义人话:同站尽量完整;跨站只给源站信息,降敏感度(✅ 以 MDN Referrer-Policy 说明为准)。
工具站若 URL 里长期挂 ?key=、?session=,更要重视——能不放敏感参数在 query,就别放。
现代浏览器能要摄像头、麦克风、地理、支付等能力。 工具站十有八九用不到,默认拒绝更干净。
示例(按需删改):
Permissions-Policy: camera=(), microphone=(), geolocation=()需要录音转写、扫码等能力时,再对自己的源放开,而不是全局 *。
没有 = 扫描器标红的物理原因。
社区常用类工具(名称因产品迭代会变,⚠️):输入域名,看缺哪些头、建议值。\ 只当清单,不当唯一真理——有的工具对 CSP 评分偏严,以你业务是否可运行为准。
头可以加在:
位置 | 适合谁 | 注意 |
|---|---|---|
CDN / 边缘(Cloudflare 等) | 静态站、多区域 | 规则全局,改一次全站生效 |
反向代理(Nginx / Caddy) | VPS 自建 | 配置即代码,可进 Git |
框架中间件(Next.js headers 等) | App Router / SSR | 和路由绑定,便于分路径策略 |
平台面板(Vercel / Netlify 头配置) | 无服务器团队 | 先查平台文档当前写法 |
原则:只在一处当「权威源」,避免 CDN 一套、应用一套互相覆盖,排错到崩溃。
以下为常见写法示意,版本与平台字段以你当前文档为准(⚠️)。不写死「某一发行版唯一正确」。
思路:在「所有页面响应」统一挂头。
伪配置清单(对照你的 next.config / _headers / Nginx):
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
X-Frame-Options: DENY
Content-Security-Policy-Report-Only: (你的策略)分路径策略(进阶):
/api/*:更严的 frame-ancestors、更窄的 connect-srcscript-src 开成筛子这是工具站真实矛盾:
你要 AdSense / 分析 / 客服挂件,CSP 又要收紧。
可执行折中:
script-src、img-src、connect-src、frame-src)一人团队规则:
Day | 主题 | 和安全的关系 |
|---|---|---|
61 | ISR 缓存 | 缓存的是「内容」;头是「每次响应的门禁」,别只缓存 HTML 忘了头 |
62 | Edge | 边缘是加安全头的好位置,但逻辑别塞太重 |
63 | CWV | 乱加的第三方脚本既拖 INP,又放大 XSS 面 |
64 | 安全头 | 浏览器侧最小可行防御 |
一句话串起来:
快(63)+ 近(62)+ 新(61)之后,还要 硬(64)。
用户留下来,不只因为「秒开」,还因为「看起来不像野站」。
Day 1(今天,60 分钟)
nosniff、Referrer-Policy、Permissions-Policy、防嵌套Day 2–3
Day 4–5
Day 6–7
误区 | 现实 |
|---|---|
「我用了 Cloudflare 就等于安全了」 | CDN ≠ 自动满分安全头,很多要自己开规则 |
「扫描全绿 = 不会被黑」 | 头只是一层;业务逻辑漏洞、依赖投毒不在此列 |
「CSP 越严越好,一次拉满」 | 容易全站白屏;先报告后拦截 |
「工具站又没账号,不用安全」 | 被挂马、被嵌套、被注入广告,照样毁品牌 |
「只给首页加头」 | 模板页、预览页、旧子域漏了 = 攻击面还在 |
一人团队最怕「知道要加,不知道贴哪」。下面给三套常见落点的对照思路(字段名以你当前面板/文档为准,⚠️):
在 server { ... } 里加(示意):
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header X-Frame-Options "DENY" always;
# CSP 先 Report-Only,确认无误再改成 Content-Security-Policy
add_header Content-Security-Policy-Report-Only "default-src 'self'; ..." always;注意:always 很关键,错误页(4xx/5xx)也要带头,不然扫描器抽到错误页照样红。
Caddy 对 https 很友好,头可以用 header 指令统一挂。思路一样:全站默认严,个别路径再放宽,别反过来。
适合静态站、多区域:
CDN 的坑:你在源站加了头,CDN 又盖一层,最后以谁为准要在 Network 面板看最终响应,不要只看源站配置截图。
Report-Only 开起来以后,控制台或报告端点会冒出一堆「违规」。别慌,先分类:
类型 | 常见原因 | 处理 |
|---|---|---|
自有域名脚本被拦 | 路径写错、用了 CDN 子域没写进策略 | 补白名单 |
内联脚本/样式 | 老模板、onclick、style 属性 | 改外链或上 nonce |
第三方统计/广告 | GA、像素、广告 iframe | 决定留不留;留就写进 script-src/frame-src |
浏览器扩展注入 | 用户本地插件 | 可忽略,别为扩展改全站策略 |
eval / 动态代码 | 老打包工具、某些 SDK | 能换 SDK 就换;短期才考虑极窄放开 |
读报告的纪律:
工具站模板页多:在 首页、工具页、文章页、带广告的页 各开一次,报告才有代表性。
格式转换、图片压缩、在线编辑类工具,安全头只是外壳,业务上还要记住:
nosniff 和正确的 Content-Type 要一起做,只加一头不够安全头解决的是「浏览器默认行为」; UGC 解决的是「你自己的业务信任边界」。 两边都空,扫描绿了也经不起真流量。
把安全头和 Day 63 的 CWV 并列,变成同一张上线表:
上线前(工具站模板变更也算上线):
[ ] https 全站,无混合内容
[ ] HSTS(https 已稳)
[ ] nosniff + Referrer-Policy + Permissions-Policy
[ ] 防嵌套(frame-ancestors / XFO)
[ ] CSP:Report-Only 或正式策略已部署
[ ] 抽查 3 个 URL 的最终响应头
[ ] 广告/登录/上传路径手点一遍
[ ] CWV:Search Console / 现场数据无新恶化一人团队的好处是决策快;坏处是没有第二个人提醒你漏了头。 所以门禁必须写进仓库或备忘,而不是留在「我下次记得」。
回到开头那句:
安全不是装一个插件。是浏览器帮你挡第一刀。
出海工具站做到 Day 64,你可能已经有了:
若安全头仍是空白,等于:
前庭打扫干净了,大门还虚掩着。
不要求你一周变成安全专家。 只要求你:6 个头进清单,和 CWV 一样成为上线门禁。
下一次加分析脚本、加广告、加客服挂件时,先问一句:
「CSP 白名单写了吗?」
这句话比任何「我们很重视安全」的口号都管用。
nosniff、Referrer、Permissions、防嵌套袁锐钦 · AI产品实操 & 出海工具站日更中。做产品、测工具、跑变现,把试过的路摊开给你看。