PHP `CSP` (Content Security Policy) 配置:缓解 XSS 攻击

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 定义可以通过 XMLHttpRequestFetch APIWebSocket 等方式连接的有效来源。
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 定义 WorkerSharedWorkerServiceWorker 脚本的有效来源。
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-toContent-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 的部署步骤

  1. 评估你的网站: 了解你的网站使用了哪些资源,以及这些资源来自哪些来源。
  2. 制定 CSP 策略: 根据你的网站的需求,制定一个合适的 CSP 策略。 从一个宽松的策略开始,逐步收紧。
  3. 部署 CSP 策略: 将 CSP 策略添加到你的 HTTP 响应头中。
  4. 监控 CSP 报告: 监控 CSP 报告,了解是否有资源被阻止加载。 根据报告调整你的 CSP 策略。
  5. 逐步收紧策略: 逐步收紧你的 CSP 策略,直到达到一个平衡点,既能保证网站的安全性,又能保证网站的正常运行。

最佳实践

  • 从一个宽松的策略开始: 不要一开始就使用过于严格的策略,否则可能会导致网站无法正常运行。
  • 使用 Content-Security-Policy-Report-Only 进行测试: 在正式部署 CSP 策略之前,先使用 Content-Security-Policy-Report-Only 进行测试,确保策略不会影响网站的正常运行。
  • 监控 CSP 报告: 定期监控 CSP 报告,了解是否有资源被阻止加载。
  • 避免使用 'unsafe-inline''unsafe-eval' 尽可能避免使用 'unsafe-inline''unsafe-eval',因为它们会增加 XSS 攻击的风险。
  • 使用 noncehash 允许内联脚本: 如果必须使用内联脚本,请使用 noncehash 属性来允许特定的内联脚本。
  • 定期更新 CSP 策略: 随着你的网站的发展,你的 CSP 策略也需要不断更新。
  • 使用 CSP 分析工具: 可以使用 CSP 分析工具来帮助你制定和测试 CSP 策略。

一些需要注意的点

  • CSP 不能完全阻止 XSS 攻击: CSP 只能降低 XSS 攻击的风险,但不能完全阻止 XSS 攻击。 仍然需要采取其他安全措施,例如输入验证和输出编码。
  • CSP 会影响网站的性能: CSP 会增加浏览器加载资源的负担,可能会影响网站的性能。 需要权衡安全性和性能。
  • CSP 的兼容性: CSP 的兼容性取决于浏览器。 需要测试你的 CSP 策略在不同的浏览器上的兼容性。
  • 错误配置 CSP 会导致网站崩溃: 如果 CSP 策略配置错误,可能会导致网站无法正常运行。 在部署 CSP 策略之前,一定要仔细测试。

总结

CSP 是一个强大的安全工具,可以有效地降低 XSS 攻击的风险。 但是,CSP 并不是万能的,仍然需要采取其他安全措施。 通过合理的配置和部署 CSP 策略,可以大大提高网站的安全性,保护用户的信息安全。

好了,今天的讲座就到这里。希望大家都能学会使用 CSP,保护自己的网站,摆脱 XSS 的魔爪! 记住,安全无小事,防患于未然! 下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注