修改子目录.htaccess的CSP未生效,父级配置仍生效问题排查
我的目录结构如下:
www/.htaccess www/club/.htaccess www/club/downloads/.htaccess
初始配置
- 根目录
www/.htaccess的CSP配置:Header always set Content-Security-Policy "frame-ancestors 'self' *.mydomain" www/club/.htaccess初始CSP配置:Header always set Content-Security-Policy "frame-ancestors 'self' *.mydomain"
更新后的子目录配置
之后我更新了子目录的.htaccess:
www/club/.htaccess改为:SetEnvIf X-Requested-With "com.myapp" isMyapp Header always set Content-Security-Policy "frame-ancestors 'self' google.com *.mydomain" env=!isMyappwww/club/downloads/.htaccess改为:SetEnvIf X-Requested-With "com.myapp" isMyapp Header always set Content-Security-Policy "frame-ancestors 'self' microsoft.com *.mydomain" env=!isMyapp
问题现象
应用请求时始终触发旧CSP规则的拒绝,拒绝信息只显示*.mydomain,新增的google.com、microsoft.com完全没生效。已清除应用缓存、重装应用,问题依旧。
更新测试
我修改了根目录www/.htaccess的CSP:
Header always set Content-Security-Policy "frame-ancestors 'self' *.yahoo.com *.mydomain"
此时应用访问正常,响应头里也能看到*.yahoo.com。
现在核心问题:为什么子目录的.htaccess无法覆盖父级的CSP配置?
问题出在Apache Header指令的默认行为和多CSP头的浏览器处理逻辑上:
Header指令默认是追加而非替换
父级.htaccess用Header always set设置了CSP头后,子目录的Header always set不会替换已有的头,而是添加第二个CSP响应头。浏览器处理多个CSP头时,会取所有规则的交集——也就是只允许所有头都认可的来源,所以父级的*.mydomain会覆盖子级新增的google.com/microsoft.com,最终表现为旧规则生效。子级需用
Header always replace替换现有头
要让子目录的CSP覆盖父级配置,需要把set改为replace,确保替换掉已有的CSP头:www/club/.htaccess修改为:SetEnvIf X-Requested-With "com.myapp" isMyapp Header always replace Content-Security-Policy "frame-ancestors 'self' google.com *.mydomain" env=!isMyappwww/club/downloads/.htaccess修改为:SetEnvIf X-Requested-With "com.myapp" isMyapp Header always replace Content-Security-Policy "frame-ancestors 'self' microsoft.com *.mydomain" env=!isMyapp
检查环境变量触发条件
确认应用请求是否真的携带了X-Requested-With: com.myapp头。如果请求里没有这个头,env=!isMyapp条件成立,子级的CSP会生效;如果请求携带了该头,子级的CSP不会被设置,此时会沿用父级的配置。可以通过浏览器开发者工具查看请求头,验证这个变量是否被正确触发。
内容的提问来源于stack exchange,提问作者rolinger

