在.htaccess中配置Content-Security-Policy (CSP)随机数(nonce)时遭遇错误,寻求问题排查帮助
嘿,我来帮你梳理一下你遇到的问题,核心问题主要出在nonce的传递顺序和Apache配置的语法错误上,咱们一步步拆解:
首先,找出你代码里的几个关键问题:
.htaccess里的SetEnv完全无效
你在.htaccess里写了:SetEnv MY_CSP_NONCE "<?php echo $_SERVER['MY_CSP_NONCE']; ?>"Apache是不会解析PHP代码的!所以这个环境变量被设置成了字符串
"<?php echo $_SERVER['MY_CSP_NONCE']; ?>",而不是你PHP生成的真实nonce值,这直接导致CSP头里的'nonce-%{ENV:MY_CSP_NONCE}'变成了无效的nonce,自然匹配不上你页面里的nonce。Apache Header指令的执行顺序早于PHP
就算你用PHP的putenv()设置了环境变量,Apache在处理.htaccess的Header指令时,PHP脚本还没运行呢,所以Apache根本拿不到PHP生成的nonce值,顺序完全反了。CSP配置的语法错误
你在style-src里嵌套了style-src-attr指令:style-src 'self' style-src-attr 'self' 'nonce-%{ENV:MY_CSP_NONCE}'这是错误的语法,style-src-attr是单独的CSP指令,不能放在style-src里面。这直接导致style-src指令无效,浏览器 fallback到了default-src,而你的default-src是
'none',自然拒绝了内联样式。
接下来是具体的修复方案:
最靠谱的方式是把CSP头的设置从.htaccess移到PHP里,这样PHP生成nonce后可以直接同步设置CSP头,完美匹配页面里的nonce。
步骤1:修改.htaccess
移除这两行内容:
SetEnv MY_CSP_NONCE "<?php echo $_SERVER['MY_CSP_NONCE']; ?>" Header always set Content-Security-Policy "expr=default-src 'none'; ..." # 整行都删掉
步骤2:修改cookiesetter.php
让它生成nonce后直接输出CSP头:
<?php // 生成安全的nonce $nonce = rtrim(strtr(base64_encode(random_bytes(64)), '+/', '-_'), '='); // 构建正确的CSP策略,注意修复style-src和style-src-attr的语法 $csp_policy = <<<CSP default-src 'none'; script-src 'self' require-trusted-types-for 'script' https://www.googletagmanager.com https://www.facebook.com https://www.twitter.com https://www.instagram.com 'nonce-$nonce' 'strict-dynamic' 'wasm-eval' 'unsafe-eval'; script-src-elem 'self'; connect-src 'self'; img-src 'self' https://storage.googleapis.com data:; video-src 'self' https://storage.googleapis.com data:; style-src 'self' 'nonce-$nonce'; style-src-attr 'self' 'nonce-$nonce'; base-uri 'none'; object-src 'none'; frame-ancestors 'self'; frame-src 'self'; sandbox allow-same-origin allow-scripts allow-popups; media-src 'self'; worker-src 'self https://*.cloudflare.com'; manifest-src 'self'; child-src 'self'; prefetch-src 'self' https://storage.googleapis.com https://www.googletagmanager.com; form-action 'self' https://www.paystack.com; font-src 'self' data:; upgrade-insecure-requests CSP; // 输出CSP头 header("Content-Security-Policy: $csp_policy"); ?>
步骤3:保留index.php里的nonce使用方式
你在index.php里的style和script标签加nonce的写法是对的,继续保留:
<?php include "cookiesetter.php" ?> <html> <head> <title>Example</title> <style nonce="<?php echo $nonce ?>"> bla bla bla </style> </head> <body> <script nonce="<?php echo $nonce ?>"> bla bla bla </script> </body> </html>
关于mod_unique_id的问题
你之前用mod_unique_id报错,大概率是因为没在Apache里启用这个模块,或者在.htaccess里的配置方式不对。不过既然用PHP生成nonce的方式更灵活可控,咱们就用上面的方案就好啦。
备注:内容来源于stack exchange,提问作者Shasha

