我们有一个单页面应用程序,它使用 Spring Boot 作为后端,React 作为前端。我们使用 PrimeReact 作为 React 的组件库。 我们将 React 应用程序打包为 Spring Boot 应用程序中的静态部分,这样我们只有一个部署文件,并且 React 应用程序由 Spring Boot 提供给用户..
更新我们的 Node.js 包后,PrimeReact 在结果页面的 body 元素中注入 nonced 内联样式。在 Spring Boot 配置中静态创建并添加到 HTTP 标头 bean 的 CSP 不喜欢随机数,并且该站点看起来确实没有样式..
Chrome 多次显示此错误:
"Refused to execute inline script because it violates the folowwing Content Security Policy directive: "script src 'self'". Either the 'unsafe-inline' keyword, a has ('sha256-*EXPLICIT-HASH-EVERY-TIME*'), or a nonce ('nonce-...') is required to enable inline execution"
我知道,为什么浏览器拒绝使用这些哈希值。但我不知道如何解决这个问题。
原包装:
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.46",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"chart.js": "^4.4.0",
"chartjs-plugin-datalabels": "^2.2.0",
"http-proxy-middleware": "^2.0.6",
"primeicons": "^6.0.1",
"primereact": "^9.6.2",
"quill": "^1.3.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.15.0",
"react-scripts": "5.0.1",
"react-transition-group": "^4.4.5",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
更新包:
"dependencies": {
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.12",
"@types/node": "^22.5.4",
"@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
"chart.js": "^4.4.4",
"chartjs-plugin-datalabels": "^2.2.0",
"http-proxy-middleware": "^3.0.2",
"primeicons": "^7.0.0",
"primereact": "^10.8.2",
"quill": "^2.0.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.1",
"react-scripts": "^5.0.1",
"react-transition-group": "^4.4.5",
"typescript": "^4.9.5",
"web-vitals": "^4.2.3"
},
PrimeReact 在 HTML-body 元素注入样式时在这个地方(hooks.esm.js)抛出异常:
var load = function load() {
if (!document || isLoaded) {
return;
}
var styleContainer = (context === null || context === void 0 ? void 0 : context.styleContainer) || document.head;
styleRef.current = getCurrentStyleRef(styleContainer);
if (!styleRef.current.isConnected) {
styleRef.current.type = 'text/css';
if (id) {
styleRef.current.id = id;
}
if (media) {
styleRef.current.media = media;
}
DomHandler.addNonce(styleRef.current, context && context.nonce || PrimeReact.nonce);
styleContainer.appendChild(styleRef.current);
if (name) {
styleRef.current.setAttribute('data-primereact-style-id', name);
}
}
styleRef.current.textContent = css;
setIsLoaded(true);
};
上面的代码是在新版本的 PrimeReact 中引入的,在 PrimeReact 9.6.2 中没有这段代码。我还没有找到为什么现在会发生这种情况以及原因的线索。
Spring Boot 中的 CSP 生成:
contentSecurityPolicyConfig -> contentSecurityPolicyConfig.policyDirectives("default-src 'self'; img-src 'self' data:;")
我们当前使用的不安全解决方法:
contentSecurityPolicyConfig -> contentSecurityPolicyConfig.policyDirectives("default-src 'self' 'unsafe-inline'; img-src 'self' data:;")
我对此有一些疑问:
任何暗示我正确(并且可能是最好)方向的答案都将受到赞赏。预先感谢。
我们找到了解决方案:
我们现在使用 HTML 内 CSP。在 React 中,我们为当前 HTML 页面生成一个随机数并将其传递给 PrimeReact。 乍一看,这看起来有点不安全:将内容传输到客户端并让客户端构建 csp,但实际上这只是对页面发出的一个请求,并且它会密封内容,以便其他内容无法被访问。已加载 csp 未覆盖的内容。
const array = new Uint32Array(1);
const nonce = crypto.getRandomValues(array)[0].toString();
function initCSP() {
let csp = "default-src 'self'; img-src 'self' data:; style-src 'self' 'nonce-{$nonce$}'".replace("{$nonce$}", nonce);
var meta = document.createElement('meta');
meta.httpEquiv = "Content-Security-Policy";
meta.content = csp;
let updated = false;
for (const element of document.getElementsByTagName('head')[0].children) {
if (element.getAttribute("http-equiv") === "Content-Security-Policy") {
element.setAttribute("content", csp);
updated = true;
}
}
if (!updated) {
document.getElementsByTagName('head')[0].insertBefore(meta, document.getElementsByTagName('head')[0].firstChild)
}
return nonce;
}
--
const config = {
nonce: nonce
}
--
<PrimeReactProvider value={config}>
...
</PrimeReactProvider>
有些代码还不是最优的,但我想你可能明白了。