本帖最后由 fzlte0 于 2026-4-26 15:04 编辑
最近想开发个chrome浏览器扩展程序manifest V2版本,实现popup界面点击后会在浏览器上新建一个tab页面,在这个页面通过Vue框架来开发。初步的代码实现如下:
[HTML] 纯文本查看 复制代码 // popup.js 打开新页面 加载插件自定义网页
let openNewTabButton = document.getElementById('openNewTab');
openNewTabButton.addEventListener('click',(event)=>{
chrome.tabs.create({
url: chrome.runtime.getURL('myVueApp.html') // Vue实现的界面
});
});
// myVueApp.html Vue 页面通过CDN引入
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.prod.js"></script>
</head>
<body>
<div id="app">{{message}}</div>
<script>
const { createApp } = Vue
createApp({
data(){
return {
message: 'hello Vue!'
}
}
}).mount('#app')
</script>
</body>
</html>
我们打算通过<script>元素引用外部CDN链接来使用Vue,https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.prod.js。运行程序,发现myVueApp.html控制台报错如下:
其中存在两个问题:
1、拒绝加载脚本'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.prod.js',因为违反了内容安全策略指令(Content Security Policy directive,CSP directive)中的"script-src 'self' blob: filesystem:"。同时,'script-src-elem'指令没有明确设置,导致回退到script-src。
2、需要'unsafe-inline'关键字,或者哈希hash ('sha256-37m87mFyQWW7DnxEUC/ottLFY1Sl1fU470G75B/RhFY='),或者一个nonce ('nonce-...') 去使能内联执行。
先了解下概念:什么是内容安全策略、内容安全策略指令、内容安全策略指令中的script-src和script-src-elem是什么及如何设置。
(一)MDN上的描述
关于浏览器插件的内容安全策略概念可以参考MDN文档Mozilla->附加组件->浏览器扩展->Content Security Policy,链接https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy。
Content Security Policy(CSP)是一种避免网站意外执行包含有恶意的内容的机制。网站通过使用服务端发送的 HTTP 标头指定 CSP。CSP 主要关注指定各种内容的合法来源,如脚本和嵌入式插件。例如,网站可以使用它来告诉浏览器应该只执行来自网站自身的 JavaScript,而不应该执行其他来源的脚本。CSP 还可以指导浏览器禁止潜在危险行为,如 eval()的使用。
和网页一样,插件可以加载其他来源的内容。例如浏览器的弹出窗口可以指定为一个 HTML 文档,它同样可以包含不同来源的 JavaScript 和 CSS,就像一个普通的网页一样。如下面的代码中的第三方脚本就类似我们的Vue CDN链接。
[HTML] 纯文本查看 复制代码 <html>
<head>
<meta charset="utf-8" />
</head>
<body>
<!--Some HTML content here-->
<!--
Include a third-party script.
See also https://developer.mozilla.org/zh-CN/docs/Web/Security/Subresource_Integrity.
-->
<script
src="https://code.jquery.com/jquery-2.2.4.js"
integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI="
crossorigin="anonymous"></script>
<!-- Include my popup's own script-->
<script src="popup.js"></script>
</body>
</html>
文档中还提到下面两点,从中我们可以知道扩展程序是有默认的安全策略的,我们开发者如果有需要可以通过manifest.json 中的 content_security_policy字段的指令值来改变安全策略,具体如何改变MDN文档中也有说明(Mozilla->Add-ons->Browser extensions->manifest.json->content_security_policy,链接:https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_security_policy):
a、插件默认运行在一个相当严格的安全策略下。参考 default content security policy。
b、插件的作者可以通过使用 manifest.json 中的 content_security_policy 关键词改变这种默认策略,但是允许的策略仍然有一定的限制。参考 content_security_policy。
(二)Bing搜索:内容安全策略(csp) 中的指令
以下是通过 HTTP 响应头设置 CSP 的示例:(服务器响应)
Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com此配置表示:默认资源(default-src)仅允许从自身加载,脚本资源(script-src)可从自身和 https://example.com 加载。
常见问题及解决方法(在html头部添加规则)
1、缺少 CSP 配置 如果未设置 CSP,浏览器将默认使用标准同源策略,可能导致 XSS 攻击。解决方法是通过 HTTP 头或 <meta> 标签启用 CSP。 示例:<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
2、配置不当导致资源加载失败 不正确的 CSP 配置可能阻止合法资源加载,例如 JS 或 CSS 文件。需确保所有必要的资源来源都被正确声明。
3、报告机制 使用 report-uri 或 report-to 指令捕获违规行为。例如:<meta http-equiv="Content-Security-Policy" content="default-src 'self'; report-uri /csp-report">
常用指令
default-src: 定义所有资源的默认加载策略。
script-src: 限制 JavaScript 的加载来源。
style-src: 限制样式表的加载来源。
img-src: 限制图片的加载来源。
(三)Bing搜索 script-src-elem
script-src-elem 指令的作用与用法123
CSP: script-src-elem - HTTP | MDN https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src-elem
内容安全策略 (CSP)_script-src-elem-CSDN博客 https://blog.csdn.net/allway2/article/details/126703214
CSP: script-src (CSP) - HTTP 中文开发手册 - 开发者手册 - 腾讯云开 …https://cloud.tencent.com/developer/section/1189876
script-src-elem是内容安全策略(CSP) 中的一项指令,用于指定 <script> 元素的 JavaScript 脚本来源。它为浏览器提供了更精细的控制,确保只加载来自可信来源的脚本,从而有效防止跨站脚本攻击(XSS)和其他安全威胁。
1、基本功能
script-src-elem 仅适用于 <script> 元素的外部脚本加载,不影响内联脚本或事件处理程序(如 onclick)。如果未定义该指令,浏览器会回退到 script-src 或 default-src 的设置。(解释了我们的第1点问题'script-src-elem'指令没有明确设置,导致回退到script-src,说明我们在manifest.json中要设置下script-src-elem指令)
(1)语法
Content-Security-Policy: script-src-elem <source>;
<source> 可以是以下之一:
具体域名:如 https://example.com
通配符:如 https://*.example.com
协议:如 https:
关键字:如 'self'(当前域)、'none'(禁止加载)、'unsafe-inline'(允许内联脚本,通常不推荐)
(2)示例
以下 CSP 规则只允许从 https://example.com 加载脚本:Content-Security-Policy: script-src-elem https://example.com;
如果页面尝试加载其他来源的脚本,例如:<script src="https://not-example.com/script.js"></script> ,浏览器将阻止该脚本加载,并在控制台中记录 CSP 违规。
2、与script-src的区别
script-src-elem 专注于 <script> 元素的外部脚本加载。
script-src 同时控制 <script> 元素、内联脚本和事件处理程序。两者可以同时使用,script-src-elem 优先级更高。
组合使用
Content-Security-Policy: script-src 'self'; script-src-elem https://example.com;此规则允许内联脚本和事件处理程序,但 <script> 元素的外部脚本只能从 https://example.com 加载。
3、注意事项
回退机制:如果未定义 script-src-elem,浏览器会依次查找 script-src 和 default-src。
浏览器兼容性:script-src-elem 是 CSP Level 3 的一部分,部分旧版浏览器可能不支持。
通过合理配置 script-src-elem,开发者可以显著提升网站的安全性,防止恶意脚本的注入和执行。
4、MDN上的关于script-src-elem指令的介绍(所有CSP指令都可以MDN查)
链接:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src-elem
CSP: script-src-elem
HTTP Content-Security-Policy(CSP 内容安全性策略)中的 script-src-elem 指令指定了 JavaScript <script> 元素的有效来源。
这个指令仅在 <script> 元素(脚本请求和块)指定有效的来源。它不适用于触发脚本执行的其他 JavaScript 源,例如内联脚本事件处理程序(onclick)、在“unsafe-eval”(不安全地执行字符串表达式)检查下的脚本执行方法和 XSLT 样式表(可以使用 script-src 为所有 JavaScript 脚本源指定有效来源,也可以使用 script-src-attr 仅为内联样式脚本处理程序指定有效源)。
语法
script-src-elem 策略可以允许一个或者多个源:Content-Security-Policy: script-src-elem <source>;Content-Security-Policy: script-src-elem <source> <source>;
接着,我们在扩展程序的清单文件manifest.json中添加"content_security_policy"键和相应的指令。注意:script-src-elem后面接url不能使用引号,否则提示script-src-elem指令无效。
// manifest.json
{...
"content_security_policy": "script-src 'self'; object-src 'self'; script-src-elem
"manifest_version": 2
}
加载后插件仍然报错:Refused to load the script 'chrome-extension://fljaoaogiijepnbnhpdcppojgmnjpbcl/background.js' because it violates the following Content Security Policy directive: "script-src-elem 这时,出现后台脚本加载失败了。
按照mdn该script-src-elem指定多个源的方式添加’self’,就可以了。
"content_security_policy": "script-src 'self'; object-src 'self'; script-src-elem https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.prod.js 'self';",
后台脚本的问题解决了,重新加载,点击popup按钮,又出现新错误:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src-elem https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.prod.js 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-37m87mFyQWW7DnxEUC/ottLFY1Sl1fU470G75B/RhFY='), or a nonce ('nonce-...') is required to enable inline execution.
script-src-elem再补充一个值'unsafe-inline'即"content_security_policy": "script-src 'self'; object-src 'self'; script-src-elem https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.prod.js 'self' 'unsafe-inline';"就正常了。
现在,打印下我们的基于Vue CDN的chrome扩展程序界面中的Vue吧。
这时,我们的message消息还没有正常显示到界面上,看到下面还有个报错。
Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'". at new Function (<anonymous>) at fu (vue.global.prod.js:1:122311) at cs (vue.global.prod.js:1:61297) at vue.global.prod.js:1:48236 at vue.global.prod.js:1:48244 at B (vue.global.prod.js:1:48263) at M (vue.global.prod.js:1:46487) at _ (vue.global.prod.js:1:43586) at X (vue.global.prod.js:1:54780) at mount (vue.global.prod.js:1:36715) Content Security Policy directive: "script-src 'self' 出错原因是不允许将字符串作为js代码执行,由于指令"script-src 'self'没有声明允许权限 'unsafe-eval'。
再次添加"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; script-src-elem https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.prod.js 'self' 'unsafe-inline';"
我们重新加载,再次运行,终于成功了,Vue打印数据输出在界面上。
|