Defaults.Exposed › 修复 › 内容安全策略(CSP)
如何修复 内容安全策略(CSP)
内容安全策略是你的网站交给每个访客浏览器的一条安全规则,明确告诉它哪些代码获准运行。没有它,一旦有恶意东西落到页面上——通过一个评论框、一个被黑的插件,或一个第三方脚本——浏览器就会随意运行它,包括在你客户输入时悄悄盗取卡号和密码的代码,而那把锁还显示着。
对您业务的关键影响: 你的网站一旦被篡改,恶意代码就能在一切看起来完全正常的情况下,直接从你自己的结账页面读走客户的支付卡和登录信息——留给你的是退款、欺诈索赔、一桩须上报的数据泄露,以及一个大客户安全团队用来搁置或扼杀生意的检查失败。
这会让您付出什么代价
- 隐藏的代码溜进你的某个页面,悄悄复制你客户在结账时输入的每一个卡号和密码,发给攻击者,而你的网站看起来完全正常——你只在欺诈投诉到来时才发现。
- 一个骗子在你真实的网站上植入一个假的「在此付款」表单,把款项收进他自己的账户;客户以为付给了你,货没到时骂你,并索回他们的钱。
- 一个大客户的安全团队扫描你的网站,发现这项基本保护被关着,把它标记出来——让你的合同搁置或丢失,直到你能证明已修好。
- 一桩追溯到缺失标准防护的泄露变成一起须上报的事故:监管方的质询、客户通知,以及一次远比那个免费修复更昂贵的名誉打击。
为什么它重要。 那把锁证明到你网站的连接是私密的,但它对访客上了页面之后哪些代码运行毫无控制。内容安全策略正是那个有控制的防护——它告诉浏览器忽略任何并非来自你信任来源的脚本,于是一个被篡改的字段、广告或插件,无法被变成盗取你客户金钱和数据的工具。它是你评分卡上的一项计分检查,值实打实的分数,也是一次专业安全审查最先查的东西之一。
这是什么,大白话版
当有人访问你的网站时,他的浏览器下载你的页面并运行上面的任何代码——那些让菜单下拉、按钮工作、支付表单提交等等的脚本。默认情况下,浏览器信任所有这些。它无从知道哪些代码真正是你的、哪些是别人偷偷塞进来的。
一个内容安全策略(常简称 CSP)是你的网站附加到每个页面上的一份简短规则清单,告诉浏览器:「只运行来自我批准的这些来源的代码,其余一概拒绝。」 这是一家谁都放进去的夜店和一家门口有宾客名单的夜店之间的区别。
它之所以如此重要,是因为网站不断被篡改——并不总是通过黑掉你的服务器,而是通过多数网站留着的那些后门:一个评论字段、一个搜索框、一个过时的插件、一个用于广告或分析的第三方脚本,或一个聊天小部件。如果攻击者哪怕把一行他自己的代码弄到你的某个页面上,浏览器就会把它当作你的来运行。从那里它能读走你客户输入的一切——卡号、密码、地址——并悄悄送往别处。内容安全策略通过拒绝运行任何来自你未批准来源的东西,关上那扇门。
这会让你付出什么代价
这不抽象。内容安全策略所防止的攻击——注入页面、从你自己客户那里盗取数据的代码——是有记录以来一些最大的刷卡泄露的幕后元凶。下面是它对一家普通企业往往如何上演:
- 隐形的结账盗刷器。 攻击者通过一个有漏洞的插件或一个被攻陷的第三方脚本,把几行代码溜上你的结账页面。你客户输入的每一个卡号、姓名和 CVV 都被实时复制并发给攻击者。你的网站看起来、用起来都完美;那把锁也在。你几周后才发现,当你的支付服务商打电话来说一簇欺诈报告全都追溯回你的店铺。现在你面对的是退款、一次强制安全审计、可能丧失收卡资格,以及一桩你可能依法须上报的泄露。
- 假的支付表单。 一个骗子往你真实的网站上注入一个以假乱真的「在此付款」框。客户信任你的品牌而输入他们的信息;钱和数据都去了攻击者那里。客户骂你——而他们没骂错,因为它发生在你的网站上。
- 丢掉的合同。 一个大客户的安全团队作为供应商尽职调查的一部分,对你的网站做一次自动扫描。一个缺失的内容安全策略立刻作为高严重度缺口冒出来。对一个采购或安全审查者而言,那一项缺失的防护读起来就是「这个供应商连基本功都不做」——于是生意搁置,等他们要求整改,或悄悄花落于通过了检查的竞争对手。
- 须上报的泄露。 当一桩数据泄露被追溯到一个缺失的、标准的、免费的防护时,它就不再是运气不好,而开始看起来像疏忽。这改变了监管方的质询、客户通知义务,以及代价——既包括罚款,也包括那个在事故结案后久久不散的名誉损害。
- 被攻陷的广告或小部件。 许多网站从外部方加载代码——广告网络、字体、支持聊天、分析。其中任何一个一旦被攻破,恶意代码就直接搭车进你的页面。内容安全策略通过只允许你信任的特定外部来源,限制了爆炸半径,于是一个供应商的泄露不会自动变成你的。
它到底是什么(细节)
一个内容安全策略以一个 HTTP 响应头的形式传递——一行你的 Web 服务器随每个页面发送的内容。它的值是一组指令,每条命名一类内容及其允许的来源。例如:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self'
用大白话说,这是:默认只从我自己的网站加载东西;只运行来自我自己网站的脚本;不允许任何老式插件;并且不让其他网站把我的网站嵌进一个框架里。
「好」长什么样。 我们的检查不只是看头是否存在——它像一个安全审查者那样,逐条指令地读这个策略,给它实际有多强评分。一个强壮的策略:
- 设一个限制性的基线(
default-src 'self'),只为你真正使用的特定可信第三方放宽它。 - 避开那些漏洞。 它不为脚本使用
'unsafe-inline'或'unsafe-eval',也不为脚本使用通配符(*)或光秃秃的协议来源(比如https:)——这些实际上重新打开了策略本该关上的那扇门。在确实需要内联脚本的地方,它使用一个 nonce 或 hash,让只有你特定批准的代码才运行。 - 用
frame-ancestors 'self'锁死框架嵌入(这也拦截了「嵌入你的网站来诓骗你客户」的攻击),并用object-src 'none'禁用遗留插件。 - 是强制执行的,而非仅报告。 一个
Content-Security-Policy-Report-Only头只观察;它提供零运行时保护。我们的检查只给它一小部分信用,绝不记为通过。你只有在策略强制执行后才受保护。
一个存在却依赖 'unsafe-inline'、'unsafe-eval' 或通配符的策略仍会得分很低——因为实际上它提供的真实保护很少。目标是一个收紧的策略,而不只是随便一个策略。
如何修复(免费,约 1–2 小时)
把这个交给你的 IT 人员或运营你网站的人——修复本身完全免费。 我们只对长期监控它是否保持就位、保持正确收费;打开它分文不取。它要花一两个小时而非几分钟的原因,是那个防止它不小心拦掉你自己网站某些部分的小心试运行步骤。
-
以仅报告模式起步——暂不强制执行。 添加一个
Content-Security-Policy-Report-Only响应头。它观察并记录「会被」拦掉什么,却不真正拦截任何东西,于是实时网站照常工作,同时你了解每个页面真正依赖什么。(重要:仅报告本身不给访客任何保护——它只是稳妥的第一步。) -
从你网站实际使用的东西出发构建策略。 审查报告,找出每一个合法的脚本、样式、字体和图片来源——你自己的域名、你的分析、你的支付服务商、你的字体托管、你的聊天小部件——把它们列为允许的来源。一个扎实的起点是
default-src 'self'加上你真正使用的可信第三方的显式条目。 -
避开那些击穿整个意义的漏洞。 远离脚本的
'unsafe-inline'和'unsafe-eval',并避免脚本的通配符来源如*和光秃秃的协议如https:——这些重新打开了策略本该关上的那个缺口。在内联脚本不可避免的地方,使用一个 nonce 或 hash,让只有你特定批准的代码才运行。 -
锁死框架嵌入和插件。 加上
frame-ancestors 'self'(这也阻止其他网站嵌入你的来诓骗你客户,并满足相关的点击劫持检查)和object-src 'none'来拦截基于遗留插件的攻击。 -
从仅报告切换到强制执行。 一旦报告干净、网站工作,就把头名称从
Content-Security-Policy-Report-Only改成Content-Security-Policy。这一步才真正交付保护——单有一个仅报告策略并不交付,也不会通过检查。你在哪里设这个头取决于你的平台:
- Cloudflare: Rules → Transform Rules → Modify Response Header → 设
Content-Security-Policy。(你也可以用 Cloudflare 做仅报告试运行。) - Nginx:
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self';" always; - Apache:
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self';" - IIS(web.config): 添加一个名为
Content-Security-Policy的自定义 HTTP 响应头,以策略为其值。 - Google Workspace / Microsoft 365: 这些运行的是你的邮件,不是你的公开网站,所以策略设在你网站实际托管的地方(上面的 Cloudflare 或你的 Web 主机),而不是你的邮件管理后台。
- Cloudflare: Rules → Transform Rules → Modify Response Header → 设
-
重新检测你的域名,确认策略现在显示为已打开、且在强制执行,没有削弱性的漏洞。
常见错误
- 止步于仅报告。 迄今最常见的错误:一个策略以仅报告模式加上,大家就翻篇了,而网站从未真正受保护。仅报告什么都不拦。你必须切换到强制执行。
- 为了让它「能用」而抓起
'unsafe-inline'。 当策略拦掉一个合法的内联脚本时,快速的办法是允许所有内联脚本——但那重新打开了策略本该关上的那个洞。改用 nonce 或 hash。 - 使用通配符。
script-src里一个光秃秃的*(或https:)允许来自任何地方的脚本,意味着策略几乎不提供真实保护,仍会得分很低。 - 忘了第三方来源。 不先列出你使用的合法外部服务(分析、字体、支付小部件)就强制一个严格策略,会拦掉你自己网站的某些部分——这恰恰是仅报告试运行步骤存在的原因。
- 只在首页上设它。 策略需要覆盖每一个页面,尤其是结账、登录和账户页面——那些才是值得攻击的。
- 把它当作那把锁的替代品。 内容安全策略和 HTTPS/HSTS 保护不同的东西。你全都要;一个不能替另一个挡着。
常见问题
我不懂技术——这个我自己能搞定吗?
你不需要懂细节。这是由运营你网站或主机的人添加的一个设置,而在 Cloudflare 这样的服务上它基本是有引导的。把下面的「如何修复」一节交给他们。它免费;唯一要当心的是,它应当先以仅观察的试运行小心铺开,以免不小心拦掉你自己网站的某些部分——而那恰恰是这些步骤所涵盖的。
我已经有那把锁和一张 SSL 证书了——我的网站不就安全了吗?
那把锁保护你页面的「传输」;它不管页面「里面」运行什么。一旦恶意代码落到页面上——通过一个被黑的插件、一个被攻陷的广告,或一个被注入的字段——那把锁不会阻止它盗取数据。内容安全策略是那个从一开始就限制允许运行什么的层。它们保护不同的东西,你两个都要。
打开这个会搞坏我的网站吗?
如果一次性激进地打开就有可能,因为它可能拦掉你实际使用的合法脚本。这正是为什么标准做法是先以「仅报告」试运行模式起步,它观察而不拦截,修好它标记的任何东西,然后才强制执行。这样做是安全的——而这个试运行步骤已内置在下面的修复里。
我们已经把它放在「仅报告」模式了——这就被覆盖了吗?
没有,而这是最常见的虚假安全感。仅报告模式观察并记录「会被」拦掉什么,但它什么都不拦——访客得到的真实保护为零。它只是稳妥的第一步。我们的检查只给仅报告一个真实策略的一小部分信用,并且不会把它记为通过。你只有切换到强制执行模式后才受保护。
这影响我们的评分,还是只是建议性的?
它影响你的评分。内容安全策略检查是计分的,在网站安全类别中最高值 25 分。一个缺失或孱弱的策略被标为高严重度,会拉低你的评分——而它恰恰是一个客户的安全问卷会问到的那类缺口。
我们的开发者加了一个策略,但分数还是很低——为什么?
一个策略可以存在却仍然孱弱。最常见的祸首是像脚本的「unsafe-inline」和「unsafe-eval」之类的漏洞,或通配符来源(一个光秃秃的 *),它们重新打开了策略本该关上的那个缺口。我们的检查逐条指令地读这个策略,并对那些弱点扣分——一个什么都允许的策略,得分比没有策略好不了多少。修复是用 nonce 或 hash 来收紧脚本规则,而不是那些漏洞。