必须启用mod_headers模块且用header always set才能使csp覆盖所有响应(含404/500),子路径需显式配置,后定义的同名header会覆盖前序设置。
在 apache 虚拟主机中配置 content-security-policy(csp)防 xss,关键不是“加一行头”,而是确保策略生效、覆盖所有响应、适配实际资源加载行为,并避免被覆盖或忽略。
必须先启用 mod_headers 模块
Apache 默认不加载 headers 模块,即使你写了 Header always set 也不会生效,且不报错——这是最常导致配置“看似正确却无效”的原因。
- Debian/Ubuntu 系统执行:
a2enmod headers && systemctl restart apache2 - RHEL/CentOS 系统检查
/etc/httpd/conf/httpd.conf,取消这行注释:LoadModule headers_module modules/mod_headers.so - 验证是否加载成功:
apachectl -M | grep headers,有输出即表示已启用
用 Header always set 确保 CSP 覆盖全部响应状态
仅用 Header set 只对 2xx 成功响应生效;而 404、500 等错误页面同样可能被 XSS 利用(比如错误信息反射注入),所以必须使用 always:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 在
<virtualhost></virtualhost>块内添加:Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; form-action 'self'; base-uri 'self';" - 注意单引号嵌套:外层用双引号包裹整个策略字符串,内部源值用单引号(如
'self') - 分号结尾不能遗漏,空格过多或引号不匹配会导致整条策略被浏览器静默忽略
按路径细化策略,尤其管理后台需更严格
CSP 不会自动继承子路径。比如你在虚拟主机根目录设了宽松策略,/admin 页面仍可能被攻击者利用——必须显式加强限制:
- 禁用内联脚本:
<location> Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'" </location> - 若该路径完全不需要外部资源,可进一步收紧:
default-src 'none'; script-src 'self'; connect-src 'self' - 多个
Header always set同名指令时,后定义的会覆盖前面的,所以位置顺序很重要
避免常见陷阱:unsafe-inline、report-uri 和后端覆盖
生产环境轻易启用 'unsafe-inline' 或 'unsafe-eval' 就等于绕过 CSP 核心防护;同时上报机制若配置不当,也会让策略形同虚设:
- 移除
'unsafe-inline'前,需将所有onclick="..."改为事件监听,内联<script></script>改用nonce或哈希方式 - 启用
report-uri "/csp-report"后,浏览器会发 POST 请求,但 Apache 默认拒绝非 GET/HEAD 的静态路径访问 → 需单独配置接收端点:<location> Require all granted </location> - 若后端(如 PHP、Node.js)也设置了 CSP 头,可能覆盖 Apache 的设置;建议统一由 Apache 注入,后端不重复设置










