PHP CSP 配置:拯救你的网站,摆脱 XSS 的魔爪!
嘿!大家好,我是你们的老朋友,今天咱们来聊点刺激的,关于网站安全的那点事儿。特别是 PHP 网站,经常被 XSS 这个磨人的小妖精骚扰。今天,我们就来学习如何用 CSP (Content Security Policy) 这把尚方宝剑,斩断 XSS 的魔爪,还咱们的网站一个清净!
想象一下,你的网站就像一个城堡,用户是你的子民,各种资源(图片、脚本、样式)是城堡里的物资。XSS 攻击就像是混进城堡的间谍,他们乔装打扮,偷偷摸摸地执行恶意代码,盗取情报,甚至篡改城堡的防御体系。CSP 的作用,就是给城堡设置一道严格的安检,只允许经过认证的物资进入,把那些可疑的家伙统统拦在外面。
啥是 CSP? 简单来说,就是告诉浏览器: "嘿,伙计,只允许加载来自以下来源的资源!"
CSP 通过 HTTP 响应头来设置,浏览器收到这个头后,会严格按照策略执行。如果加载的资源不符合策略,浏览器会拒绝加载,并在控制台报错。
那么,CSP 到底能干啥?
- 降低 XSS 风险: 这是 CSP 最主要的作用。通过限制可信任的资源来源,可以有效地阻止恶意脚本的执行。
- 报告违规行为: CSP 可以配置成只报告违规行为,而不实际阻止资源加载。这对于测试和调试 CSP 策略非常有用。
- 增强网站安全性: CSP 可以帮助你发现网站中潜在的安全漏洞,例如使用了不安全的第三方库。
CSP 的语法结构
CSP 的语法比较简单,由指令和指令值组成。指令告诉浏览器要限制哪种类型的资源,指令值则指定允许的来源。
Content-Security-Policy: <指令> <指令值>; <指令> <指令值>; ...
常用的 CSP 指令
指令 | 描述 |
---|---|
default-src |
定义所有其他资源类型的默认来源。如果某个资源类型没有显式指定来源,则使用 default-src 的值。 |
script-src |
定义 JavaScript 脚本的有效来源。 |
style-src |
定义 CSS 样式的有效来源。 |
img-src |
定义图片的有效来源。 |
font-src |
定义字体的有效来源。 |
connect-src |
定义可以通过 XMLHttpRequest 、Fetch API 、WebSocket 等方式连接的有效来源。 |
media-src |
定义媒体文件(例如视频和音频)的有效来源。 |
object-src |
定义 <object> 、<embed> 和 <applet> 元素的有效来源。 强烈建议避免使用这些元素,因为它们可能存在安全风险。 |
base-uri |
定义 <base> 元素的有效来源。 |
form-action |
定义表单提交的有效目标。 |
frame-ancestors |
定义可以嵌入当前页面的有效来源。 用于防止点击劫持攻击。 |
report-uri |
指定一个 URL,浏览器会将 CSP 违规报告发送到该 URL。 已弃用,推荐使用 report-to 。 |
report-to |
指定一个或多个端点,浏览器会将 CSP 违规报告发送到这些端点。 需要配合 Content-Security-Policy-Report-Only 使用。 |
worker-src |
定义 Worker 、SharedWorker 或 ServiceWorker 脚本的有效来源。 |
manifest-src |
定义 manifest 文件的有效来源。 |
upgrade-insecure-requests |
指示浏览器自动将网站上的所有 HTTP URL 升级为 HTTPS。 这是一个非常有用的指令,可以提高网站的安全性。 |
block-all-mixed-content |
指示浏览器阻止网站上的所有混合内容(即通过 HTTP 加载的 HTTPS 页面上的资源)。 类似于 upgrade-insecure-requests ,但更严格。 |
指令值详解
*
: 允许来自任何来源的资源。 谨慎使用,因为它会降低 CSP 的安全性。'self'
: 允许来自当前域名(包括协议和端口)的资源。'none'
: 禁止加载任何资源。'unsafe-inline'
: 允许使用内联 JavaScript 脚本和 CSS 样式。 强烈建议避免使用,因为它会增加 XSS 攻击的风险。'unsafe-eval'
: 允许使用eval()
函数和new Function()
构造函数。 强烈建议避免使用,因为它会增加 XSS 攻击的风险。'unsafe-hashes'
: 允许特定的内联事件处理程序,例如onclick
。 同样不推荐使用,除非你真的知道自己在做什么。data:
: 允许使用data:
URL 方案加载资源。 例如,允许内联 Base64 编码的图片。mediastream:
: 允许使用mediastream:
URL 方案加载资源。 用于访问用户的摄像头和麦克风。blob:
: 允许使用blob:
URL 方案加载资源。 用于从 JavaScript 创建的二进制数据。filesystem:
: 允许使用filesystem:
URL 方案加载资源。 用于访问用户的本地文件系统。https:
: 允许使用 HTTPS 协议加载资源。域名
: 允许来自特定域名的资源。 例如,example.com
。子域名
: 允许来自特定子域名的资源。 例如,*.example.com
。nonce-<base64 编码的随机数>
: 允许执行具有匹配nonce
属性的内联脚本。 这是比'unsafe-inline'
更安全的选择。sha256-<base64 编码的哈希值>
、sha384-<base64 编码的哈希值>
、sha512-<base64 编码的哈希值>
: 允许执行具有匹配哈希值的内联脚本。 也是比'unsafe-inline'
更安全的选择。report-uri URL
: 定义一个 URL,浏览器会将 CSP 违规报告发送到该 URL。(已弃用,建议使用report-to
)report-to 指令值
: 定义一个或多个端点,浏览器会将 CSP 违规报告发送到这些端点。 需要配合Content-Security-Policy-Report-Only
使用。
PHP 中设置 CSP
在 PHP 中设置 CSP 非常简单,只需要使用 header()
函数设置 Content-Security-Policy
响应头即可。
<?php
// 设置 CSP 策略
header("Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:;");
// 其他 PHP 代码
?>
一个更复杂的例子,包含 report-to
和 Content-Security-Policy-Report-Only
<?php
// 定义 report-to 端点
$reportTo = [
"group" => "csp-endpoint",
"max_age" => 31536000, // 一年
"endpoints" => [
[
"url" => "/csp-report" // 你的报告接收 URL
]
]
];
// 将 report-to 端点编码为 JSON
$reportToHeader = json_encode($reportTo);
// 设置 Content-Security-Policy-Report-Only 响应头
header("Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-to csp-endpoint");
// 设置 Report-To 响应头
header("Report-To: " . $reportToHeader);
// 其他 PHP 代码
?>
在这个例子中:
Content-Security-Policy-Report-Only
:这个头表示策略只用于报告违规行为,不会阻止任何资源加载。这对于测试 CSP 策略非常有用。report-to csp-endpoint
:这个指令告诉浏览器将违规报告发送到名为csp-endpoint
的端点。Report-To
:这个头定义了csp-endpoint
端点的配置,包括报告接收 URL、最大缓存时间等。/csp-report
:这是你服务器上接收 CSP 报告的 URL。你需要编写相应的代码来处理这些报告。
CSP 策略示例
-
最严格的策略:
Content-Security-Policy: default-src 'none'; script-src 'none'; style-src 'none'; img-src 'none'; connect-src 'none'; font-src 'none'; object-src 'none'; media-src 'none';
这个策略禁止加载任何资源,只允许显示静态 HTML 内容。 适用于高度安全的网站,例如静态文档网站。
-
允许加载来自当前域名和 CDN 的资源的策略:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' https://cdn.example.com; img-src 'self' https://cdn.example.com data:; font-src 'self' https://cdn.example.com; connect-src 'self';
这个策略允许加载来自当前域名和
cdn.example.com
的 JavaScript 脚本、CSS 样式、图片和字体。data:
允许内联 Base64 编码的图片。connect-src 'self'
允许与当前域名建立连接(例如,AJAX 请求)。 -
使用
nonce
允许内联脚本的策略:<?php $nonce = base64_encode(random_bytes(16)); header("Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-" . $nonce . "'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;"); ?> <script nonce="<?php echo $nonce; ?>"> // 内联 JavaScript 代码 console.log("Hello from inline script!"); </script>
这个策略使用
nonce
属性来允许特定的内联脚本。nonce
是一个随机数,需要在 HTTP 响应头和 HTML 代码中保持一致。 每次页面加载时,都需要生成一个新的nonce
值。 -
使用
hash
允许内联脚本的策略:Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-YOUR_SCRIPT_HASH'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;
你需要计算内联脚本的 SHA256 哈希值,并将哈希值添加到 CSP 策略中。 这种方法比使用
nonce
更麻烦,但是可以在不需要动态生成nonce
值的情况下允许特定的内联脚本。
CSP 的部署步骤
- 评估你的网站: 了解你的网站使用了哪些资源,以及这些资源来自哪些来源。
- 制定 CSP 策略: 根据你的网站的需求,制定一个合适的 CSP 策略。 从一个宽松的策略开始,逐步收紧。
- 部署 CSP 策略: 将 CSP 策略添加到你的 HTTP 响应头中。
- 监控 CSP 报告: 监控 CSP 报告,了解是否有资源被阻止加载。 根据报告调整你的 CSP 策略。
- 逐步收紧策略: 逐步收紧你的 CSP 策略,直到达到一个平衡点,既能保证网站的安全性,又能保证网站的正常运行。
最佳实践
- 从一个宽松的策略开始: 不要一开始就使用过于严格的策略,否则可能会导致网站无法正常运行。
- 使用
Content-Security-Policy-Report-Only
进行测试: 在正式部署 CSP 策略之前,先使用Content-Security-Policy-Report-Only
进行测试,确保策略不会影响网站的正常运行。 - 监控 CSP 报告: 定期监控 CSP 报告,了解是否有资源被阻止加载。
- 避免使用
'unsafe-inline'
和'unsafe-eval'
: 尽可能避免使用'unsafe-inline'
和'unsafe-eval'
,因为它们会增加 XSS 攻击的风险。 - 使用
nonce
或hash
允许内联脚本: 如果必须使用内联脚本,请使用nonce
或hash
属性来允许特定的内联脚本。 - 定期更新 CSP 策略: 随着你的网站的发展,你的 CSP 策略也需要不断更新。
- 使用 CSP 分析工具: 可以使用 CSP 分析工具来帮助你制定和测试 CSP 策略。
一些需要注意的点
- CSP 不能完全阻止 XSS 攻击: CSP 只能降低 XSS 攻击的风险,但不能完全阻止 XSS 攻击。 仍然需要采取其他安全措施,例如输入验证和输出编码。
- CSP 会影响网站的性能: CSP 会增加浏览器加载资源的负担,可能会影响网站的性能。 需要权衡安全性和性能。
- CSP 的兼容性: CSP 的兼容性取决于浏览器。 需要测试你的 CSP 策略在不同的浏览器上的兼容性。
- 错误配置 CSP 会导致网站崩溃: 如果 CSP 策略配置错误,可能会导致网站无法正常运行。 在部署 CSP 策略之前,一定要仔细测试。
总结
CSP 是一个强大的安全工具,可以有效地降低 XSS 攻击的风险。 但是,CSP 并不是万能的,仍然需要采取其他安全措施。 通过合理的配置和部署 CSP 策略,可以大大提高网站的安全性,保护用户的信息安全。
好了,今天的讲座就到这里。希望大家都能学会使用 CSP,保护自己的网站,摆脱 XSS 的魔爪! 记住,安全无小事,防患于未然! 下次再见!