如何解决Chrome扩展新窗口脚本被CSP阻止的问题?
我开发了一个基础Chrome扩展,按下**ctrl + shift + ~**时会打开一个新窗口,窗口内是我常用的工具菜单。核心代码如下:
var newHTML = ``; var map = {}; window.addEventListener('keydown', (keyPressed) => { switch(keyPressed.key){ case "~": if(map.Control === true && map.Shift === true){ // 打开空白窗口 var w = window.open('', "Menu", "width=600, height=475, scrollbars=no"); // 向新窗口写入HTML内容 w.document.write(newHTML); } break; case "Control": map.Control = true; break; case "Shift": map.Shift = true; break; } }); // 监听按键抬起事件 window.addEventListener('keyup', (keyPressed) => { switch(keyPressed.key){ case "Control": map.Control = false; break; case "Shift": map.Shift = false; break; } });
打开新窗口的功能正常,但添加按钮后出现问题:按钮用于页面切换,原本想用本地文件链接:
<a src="file_location">Link 1</a>
但扩展不允许本地文件链接,改用按钮实现后,按钮始终无法工作。
尝试添加以下代码:
<!-- 写入newHTML中的内容 --> <button id="myButton">button</button> <script src="inline.js"></script>
// inline.js内容 document.getElementById("myButton").addEventListener("click", () => { console.log('hi'); });
收到错误提示:
Refused to load the script 'https://www.linkedin.com/inlineTest.js' because it violates the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval' 'inline-speculation-rules' http://localhost:* http://127.0.0.1:*". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
我尝试过通过meta标签设置CSP绕过限制:
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; style-src * 'unsafe-inline'; img-src * data:; connect-src *; font-src *; object-src *;">
也试过用nonce,都没效果。求可行的解决办法?
解决办法
1. 直接内联脚本逻辑(避免外部脚本文件)
Chrome扩展对about:blank窗口的CSP限制严格,meta标签无法覆盖扩展级别的CSP规则。可以直接把脚本逻辑写在newHTML中,通过内联方式绑定事件:
var newHTML = ` <button id="myButton">button</button> <script> document.getElementById("myButton").addEventListener("click", () => { console.log('hi'); // 在这里编写页面切换逻辑 }); <\/script> `;
注意:内联脚本需要在扩展的manifest.json中配置允许unsafe-inline,具体配置见下文。
2. 配置扩展Manifest的Content Security Policy
Chrome扩展的CSP必须在manifest.json中声明,meta标签无效。根据Manifest版本不同,配置方式如下:
Manifest V3
{ "manifest_version": 3, "name": "你的扩展名称", "version": "1.0", "content_security_policy": { "extension_pages": "script-src 'self' 'unsafe-inline'; object-src 'none';" }, // 其他扩展配置项 }
如果想更安全,可计算内联脚本的SHA-256哈希值替换unsafe-inline:
"content_security_policy": { "extension_pages": "script-src 'self' 'sha256-你的内联脚本哈希值'; object-src 'none';" }
Manifest V2
{ "manifest_version": 2, "name": "你的扩展名称", "version": "1.0", "content_security_policy": "script-src 'self' 'unsafe-inline'; object-src 'none';" }
3. 加载扩展内部页面(推荐)
把工具菜单页面放在扩展目录中,用扩展合法URL打开,完全规避CSP问题:
// 替换原来的window.open逻辑 var toolPageUrl = chrome.runtime.getURL('tool-menu.html'); var w = window.open(toolPageUrl, "Menu", "width=600, height=475, scrollbars=no");
将tool-menu.html放在扩展根目录,页面内的脚本、样式都能正常加载,无需额外配置危险的CSP规则。
内容的提问来源于stack exchange,提问作者user25853819

