本文目录导读:

为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");
关键注意事项
- 逐步实施:先使用Report-Only模式测试,再强制实施
- 非内联脚本:优先使用nonce或hash,避免
'unsafe-inline' - 白名单最小化:只允许必要的域名和来源
- :使用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和其他代码注入攻击。