martijnc/php-csp

此包已 废弃 并不再维护。未建议替代包。

PHP 内容安全策略助手

1.0.2 2015-11-27 09:08 UTC

This package is not auto-updated.

Last update: 2024-07-20 15:21:43 UTC


README

A PHP helper class to dynamically construct Content Security Policy headers as defined by the W3C in the Content Security Policy specification (http://www.w3.org/TR/CSP2/).

如何使用

php-csp 添加到您的项目中,创建一个 ContentSecurityPolicyHeaderBuilder 类的实例,并使用它来设置您的CSP策略。一旦策略完成,使用 ContentSecurityPolicyHeaderBuilder::getHeaders() 获取您的CSP头。

use Phpcsp\Security\ContentSecurityPolicyHeaderBuilder;

$policy = new ContentSecurityPolicyHeaderBuilder();

// Set the script-src directive to 'none'
$policy->addSourceExpression(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_SCRIPT_SRC, 'none');

// Enable the browsers xss blocking features
$policy->setReflectedXssPolicy(ContentSecurityPolicyHeaderBuilder::REFLECTED_XSS_BLOCK);

// Set a report URL
$policy->setReportUri('https://example.com/csp/report.php');

// Get your CSP headers
$headers = $policy->getHeaders(false);

ContentSecurityPolicy::getHeaders() 返回一个您应该发送的HTTP头数组。对于上面的示例,这将得到以下数组

array (size=1)
  0 => 
    array (size=2)
      'name' => string 'Content-Security-Policy' (length=23)
      'value' => string 'script-src 'none'; reflected-xss block; report-uri https://example.com/csp/report.php;' (length=86)

源表达式

此类的最直接用途是通过添加您选择的源到指令,例如在这个例子中

use Phpcsp\Security\ContentSecurityPolicyHeaderBuilder;

$policy = new ContentSecurityPolicyHeaderBuilder();

// Set the default-src directive to 'none'
$policy->addSourceExpression(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_DEFAULT_SRC, 'none');

// Add a single origin for the script-src directive
$policy->addSourceExpression(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_SCRIPT_SRC, 'https://example.com/scripts/');

// Add a single origin for the style-src directive
$policy->addSourceExpression(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_STYLE_SRC, 'https://example.com/style/');

foreach ($policy->getHeaders(true) as $header) {
    header(sprintf('%s: %s', $header['name'], $header['value']));
}

此示例将输出以下头

array (size=1)
  0 => 
    array (size=2)
      'name' => string 'Content-Security-Policy' (length=23)
      'value' => string 'default-src 'none'; script-src https://example.com/scripts/; style-src https://example.com/style/;' (length=98)

源集

您可以定义源集并将它们链接到您想要的任何CSP指令。例如

use Phpcsp\Security\ContentSecurityPolicyHeaderBuilder;

$policy = new ContentSecurityPolicyHeaderBuilder();

// Set the default-src directive to 'none'
$policy->addSourceExpression(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_DEFAULT_SRC, 'none');

// Define two source sets
$policy->defineSourceSet('my-scripts-cdn', [
    'https://cdn-scripts1.example.com/scripts/',
    'https://cdn-scripts2.example.com/scripts/'
]);

$policy->defineSourceSet('my-style-cdn', [
    'https://cdn-style1.example.com/css/',
    'https://cdn-style2.example.com/css/'
]);

// Add both to a directive
$policy->addSourceSet(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_SCRIPT_SRC, 'my-scripts-cdn');
$policy->addSourceSet(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_STYLE_SRC, 'my-style-cdn');
$headers = $policy->getHeaders(false);

将导致以下头

array (size=1)
  0 => 
    array (size=2)
      'name' => string 'Content-Security-Policy' (length=23)
      'value' => string 'default-src 'none'; script-src https://cdn-scripts1.example.com/scripts/ https://cdn-scripts2.example.com/scripts/; style-src https://cdn-style1.example.com/css/ https://cdn-style2.example.com/css/;' (length=198)

非ces

CSP阻止内联脚本,但可以通过将unsafe-inline添加到script-src指令来再次启用它们。这样做将违背使用CSP的整个目的,因此不推荐使用unsafe-inline。如果您出于任何原因需要内联脚本,应使用非ces。非ces是您添加到script-src指令和您网页上允许的内联脚本标签的随机字符串,如下例所示

use Phpcsp\Security\ContentSecurityPolicyHeaderBuilder;

$policy = new ContentSecurityPolicyHeaderBuilder();

// Set the default-src directive to 'none'
$policy->addSourceExpression(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_DEFAULT_SRC, 'none');

$myScriptNonce = 'thisShouldBeRandom';

// Add the nonce to the script-src directive
$policy->addNonce(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_SCRIPT_SRC, $myScriptNonce);

foreach ($policy->getHeaders(true) as $header) {
    header(sprintf('%s: %s', $header['name'], $header['value']));
}

将导致以下头

array (size=1)
  0 => 
    array (size=2)
      'name' => string 'Content-Security-Policy' (length=23)
      'value' => string 'default-src 'none'; script-src 'nonce-thisShouldBeRandom';' (length=58)

您的HTML应如下所示

<script>
    // This would be blocked because it has no nonce
</script>

<script nonce="thisIsAWrongNonce">
   // This would be blocked because the nonce is invalid
</script>

<script nonce="thisShouldBeRandom">
    // This would work fine
</script>

非ces应针对每个请求是随机的,这样攻击者就无法预测非ces值。

哈希

如果您的应用程序需要内联脚本,您可以将源的SHA256、SHA384或SHA512哈希作为策略中script-src指令的一部分来提供,以允许脚本运行。这样您就不需要启用unsafe-inline

违规报告

CSP为您提供接收CSP违规报告的选项。每次页面加载被您的CSP策略阻止的资源时,浏览器都会将一个JSON对象提交到您在策略中指定的URL。在以下示例中,这些报告将发送到https://example.com/csp/report.php

use Phpcsp\Security\ContentSecurityPolicyHeaderBuilder;

$policy = new ContentSecurityPolicyHeaderBuilder();

// Set the script-src directive to 'none'
$policy->addSourceExpression(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_SCRIPT_SRC, 'https://example.com/scripts/');

// Set a report URL
$policy->setReportUri('https://example.com/csp/report.php');

您还可以使用仅报告模式下的CSP。此模式适用于您在现有网站上实施CSP而不会破坏网站的情况。每次资源加载违反您的CSP策略时,浏览器都会发送违规报告,但实际上不会阻止资源。

// Set a report URL
$policy->setReportUri('https://example.com/csp/report.php');

// Use report only mode
$policy->enforcePolicy(false);

旧版头支持

此类还提供对一些被CSP取代的旧版头的支持。目前它支持X-XSS-ProtectionX-Frame-Options头。

use Phpcsp\Security\ContentSecurityPolicyHeaderBuilder;

$policy = new ContentSecurityPolicyHeaderBuilder();

// Enable the browsers xss blocking features
$policy->setReflectedXssPolicy(ContentSecurityPolicyHeaderBuilder::REFLECTED_XSS_BLOCK);

// Set the 'X-Frame-Options' header
$policy->setFrameOptions(ContentSecurityPolicyHeaderBuilder::FRAME_OPTION_SAME_ORIGIN);

// Get your CSP headers, including legacy headers
$headers = $policy->getHeaders(true);

foreach ($headers as $header) {
    header(sprintf('%s: %s', $header['name'], $header['value']));
}

这将导致以下头

array (size=3)
  0 => 
    array (size=2)
      'name' => string 'Content-Security-Policy' (length=23)
      'value' => string 'script-src 'none'; reflected-xss block; report-uri https://example.com/csp/report.php;' (length=86)
  1 => 
    array (size=2)
      'name' => string 'X-XSS-Protection' (length=16)
      'value' => string '1; mode=block' (length=13)
  2 => 
    array (size=2)
      'name' => string 'X-Frame-Options' (length=15)
      'value' => string 'SAMEORIGIN' (length=10)