如何为PHP项目配置内容安全策略?

wen PHP项目 4

本文目录导读:

如何为PHP项目配置内容安全策略?

  1. 基础配置方法
  2. PHP项目完整配置示例
  3. 常见场景的CSP配置
  4. 中间件方式实现(适用于框架)
  5. 调试与报告
  6. 关键注意事项

为PHP项目配置内容安全策略(CSP)主要通过HTTP头部实现,以下是详细的配置方法和最佳实践:

基础配置方法

通过PHP header() 函数设置

<?php
// 基础CSP配置
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'");
?>

在 .htaccess 文件中配置(Apache)

<IfModule mod_headers.c>
    Header set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self';"
</IfModule>

在 Nginx 配置中设置

add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self';";

PHP项目完整配置示例

创建CSP配置类

<?php
class CSPManager {
    private $directives = [];
    private $reportOnly = false;
    public function __construct() {
        // 设置默认值
        $this->directives = [
            'default-src' => "'self'",
            'script-src' => "'self'",
            'style-src' => "'self'",
            'img-src' => "'self'",
            'font-src' => "'self'",
            'connect-src' => "'self'",
            'frame-src' => "'self'",
            'object-src' => "'none'",
            'base-uri' => "'self'",
            'form-action' => "'self'",
        ];
    }
    public function addDirective($directive, $value) {
        $this->directives[$directive] = $value;
        return $this;
    }
    public function removeDirective($directive) {
        unset($this->directives[$directive]);
        return $this;
    }
    public function setReportOnly($reportOnly = true) {
        $this->reportOnly = $reportOnly;
        return $this;
    }
    public function addReportUri($uri) {
        $this->directives['report-uri'] = $uri;
        return $this;
    }
    public function generatePolicy() {
        $policy = '';
        foreach ($this->directives as $directive => $value) {
            if ($value === null) continue;
            $policy .= "$directive $value; ";
        }
        return rtrim($policy);
    }
    public function apply() {
        $policy = $this->generatePolicy();
        $header = $this->reportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy';
        header("$header: $policy");
    }
}

使用CSP管理器

<?php
require_once 'CSPManager.php';
// 初始化CSP
$csp = new CSPManager();
// 全局设置 - 允许同源资源
$csp->addDirective('default-src', "'self'")
    // 允许内联脚本和样式(谨慎使用)
    ->addDirective('script-src', "'self' 'unsafe-inline' 'unsafe-eval'")
    ->addDirective('style-src', "'self' 'unsafe-inline'")
    // 允许图片来自同源和data URI
    ->addDirective('img-src', "'self' data: https://trusted-cdn.com")
    // 允许字体来自同源和Google Fonts
    ->addDirective('font-src', "'self' https://fonts.gstatic.com")
    // 允许连接同源和API端点
    ->addDirective('connect-src', "'self' https://api.example.com")
    // 设置报告URI
    ->addReportUri('/csp-violation-endpoint.php');
// 应用CSP
$csp->apply();

常见场景的CSP配置

使用CDN的项目

header("Content-Security-Policy: 
    default-src 'self'; 
    script-src 'self' https://cdnjs.cloudflare.com https://code.jquery.com; 
    style-src 'self' https://fonts.googleapis.com https://cdnjs.cloudflare.com; 
    font-src 'self' https://fonts.gstatic.com; 
    img-src 'self' data: https://*.cloudfront.net;
");

使用Google Analytics

header("Content-Security-Policy: 
    default-src 'self'; 
    script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com; 
    img-src 'self' https://www.google-analytics.com https://stats.g.doubleclick.net;
    connect-src 'self' https://www.google-analytics.com;
");

包含iframe嵌入

header("Content-Security-Policy: 
    default-src 'self'; 
    frame-src 'self' https://www.youtube.com https://player.vimeo.com;
    script-src 'self' https://www.youtube.com;
");

中间件方式实现(适用于框架)

Laravel示例

<?php
namespace App\Http\Middleware;
use Closure;
class ContentSecurityPolicy
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        $csp = "default-src 'self'; " .
               "script-src 'self' 'unsafe-inline'; " .
               "style-src 'self' 'unsafe-inline'; " .
               "img-src 'self' data:; " .
               "font-src 'self' data:; " .
               "connect-src 'self';";
        $response->header('Content-Security-Policy', $csp);
        return $response;
    }
}

Symfony示例

<?php
// config/packages/security.yaml
framework:
    http_method_override: true
    php_errors:
        log: true
# 在控制器或事件监听器中设置
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
class CSPListener
{
    public function onKernelResponse(ResponseEvent $event)
    {
        $response = $event->getResponse();
        $response->headers->set('Content-Security-Policy', "default-src 'self';");
    }
}

调试与报告

设置CSP报告端点

<?php
// csp-violation-endpoint.php
$data = file_get_contents('php://input');
if ($data) {
    $violation = json_decode($data, true);
    // 记录违规报告
    error_log('CSP Violation: ' . print_r($violation, true));
    // 可以存储到数据库
    $db = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
    $stmt = $db->prepare("INSERT INTO csp_reports (document_uri, violated_directive, blocked_uri, created_at) VALUES (?, ?, ?, NOW())");
    $stmt->execute([
        $violation['csp-report']['document-uri'],
        $violation['csp-report']['violated-directive'],
        $violation['csp-report']['blocked-uri'],
    ]);
}

使用报告模式调试

<?php
// 先使用Report-Only模式测试
header("Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-violation-endpoint.php");
// 收集报告没有问题后,切换到强制执行
// header("Content-Security-Policy: default-src 'self'; report-uri /csp-violation-endpoint.php");

关键注意事项

  1. 逐步实施:先使用Report-Only模式测试,再强制实施
  2. 非内联脚本:优先使用nonce或hash,避免 'unsafe-inline'
  3. 白名单最小化:只允许必要的域名和来源
  4. :使用nonce处理动态创建的脚本

使用nonce示例

<?php
$nonce = base64_encode(random_bytes(16));
header("Content-Security-Policy: script-src 'self' 'nonce-$nonce';");
?>
<script nonce="<?= $nonce ?>">
    // 这个脚本会被允许执行
    console.log('Allowed script');
</script>

通过以上配置,你可以为PHP项目实现全面的内容安全策略,有效防御XSS和其他代码注入攻击。

抱歉,评论功能暂时关闭!