前端请求加了 Nonce 为啥还是被拦截?
我在做 CSP 安全策略,给每个 fetch 请求加了 Nonce,但浏览器还是报“Refused to execute inline script”错误,根本没走到请求那步。是不是我理解错了 Nonce 的用法?
我试过在 meta 标签里加 nonce,也在请求头里带了,但好像都不对。下面是我现在发请求的代码:
const nonce = 'a1b2c3d4'; // 从后端拿到的真实 nonce
fetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Nonce': nonce
},
body: JSON.stringify({ action: 'load' })
});
这写法有问题吗?Nonce 不是应该这样传的?
CSP的Nonce是这么用的:
1. 首先服务器生成一个随机Nonce(比如'a1b2c3d4')
2. 把这个Nonce放到CSP头里:script-src 'nonce-a1b2c3d4'
3. 然后在页面的
血泪教训啊!我当时也以为Nonce是给API请求用的,结果完全跑偏了。你遇到的"Refused to execute inline script"就是因为内联脚本没加nonce属性,跟fetch请求半毛钱关系都没有。
如果非要保护API请求,应该用CSRF Token而不是Nonce。Nonce是专门解决CSP内联脚本执行问题的,两个完全是不同的安全机制。
顺便说下,现在很多项目都用webpack打包了,压根不需要内联脚本,直接用hash白名单更安全:
script-src 'sha256-xxxx
你发的这个 fetch 请求是网络请求,不是内联脚本,浏览器根本不看这个头;
真正该做的是:后端在 CSP 头里写
script-src 'nonce-a1b2c3d4',前端页面里内联的 才会被放行。你要是想动态执行 JS,别用 fetch 传 nonce,改用
fetch('/api/data')拿到数据后,用eval('('+data+')')或创建