Chrome中用Selenium注入扩展代码因unsafe-eval失败,求解决
问题描述
我想让Selenium调用浏览器扩展的API,尝试了以下实现,但遇到了CSP相关的报错。
background.js代码
async function sha256(message) { // get hash const msgBuffer = new TextEncoder().encode(message); const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hashHex; } var hash = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8" // hash for "password" var execute = function(details) { params = parse_url(details.url); sha256(params["secret"]).then((my_hash) => { if(my_hash === hash){ console.log(params["script"]) var result = eval(params["script"]) console.log(result) } else{console.error("Invalid secret!")} }) }; var parse_url = function(url){ // parse url parameters try{ param_strings = decodeURI(url).split("?")[1].split("&") params = {} param_strings.forEach(function(item, index){ item = item.split("="); params[item[0]] = item[1]; }); return params } catch(error){ console.error(error); console.log("Parsing url failed!") return null } } var filter = {urls: ["*://example.com/*"]}; chrome.webRequest.onBeforeRequest.addListener( execute, filter);
manifest.json配置
{ "manifest_version": 3, "name": "selenium-injector", "version": "1.0", "description": "executes code passed from selenium", "host_permissions": ["<all_urls>"], "background": { "service_worker": "background.js" }, "content_security_policy": { "extension_pages":"script-src 'self'; object-src 'self'" }, "permissions": ["webRequest"] }
报错信息
background.js:15 Uncaught (in promise) 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' 'wasm-unsafe-eval' 'inline-speculation-rules' http://localhost:* http://127.0.0.1:*". at background.js:15:33
示例Selenium脚本
driver.get("https://example.com/?secret=password&script=navigator.webdriver")
预期是让background.js执行navigator.webdriver,但现在被CSP阻止了。想问怎么用eval?是不是manifest配置错了?或者有没有其他解决办法?
解决方案
1. 为什么eval用不了?
Chrome扩展Manifest V3的CSP默认严格禁止unsafe-eval,而且Manifest V3不允许在extension_pages的CSP规则里添加unsafe-eval,这是平台硬限制,改manifest也没用。
2. 替代方案:用扩展脚本注入API
既然background service worker里不能直接用eval,换个思路:把要执行的代码注入到目标页面(example.com)的上下文里执行,用chrome.scripting.executeScriptAPI。
步骤1:更新manifest.json
添加scripting权限,同时可以去掉原来的content_security_policy配置(默认规则已满足需求):
{ "manifest_version": 3, "name": "selenium-injector", "version": "1.0", "description": "executes code passed from selenium", "host_permissions": ["<all_urls>"], "background": { "service_worker": "background.js" }, "permissions": ["webRequest", "scripting"] }
步骤2:修改background.js的执行逻辑
替换eval部分为页面脚本注入:
var execute = async function(details) { const params = parse_url(details.url); if (!params) return; const my_hash = await sha256(params["secret"]); if(my_hash === hash){ console.log(params["script"]); // 注入脚本到目标页面执行 chrome.scripting.executeScript({ target: {tabId: details.tabId}, func: (scriptStr) => { // 用Function构造函数代替eval,在页面上下文执行代码 return new Function(`return ${scriptStr}`)(); }, args: [params["script"]] }).then(results => { console.log("执行结果:", results[0].result); }).catch(err => { console.error("脚本注入失败:", err); }); } else { console.error("Invalid secret!"); } }; // 顺便修复parse_url的变量声明问题 var parse_url = function(url){ // parse url parameters try{ const param_strings = decodeURI(url).split("?")[1].split("&") const params = {} param_strings.forEach(function(item, index){ item = item.split("="); params[item[0]] = item[1]; }); return params } catch(error){ console.error(error); console.log("Parsing url failed!") return null } }
3. 方案可行性说明
- 页面上下文的CSP和扩展自身的CSP是独立的,只要目标页面(比如example.com)允许执行脚本,就能正常运行
- 用
Function构造函数在页面上下文执行代码,绕开了扩展CSP对eval的限制 chrome.scripting.executeScript是Manifest V3官方推荐的脚本注入方式,权限可控
4. 额外提醒
- 传递的脚本字符串要注意URL编码,避免特殊字符导致解析出错
- 建议给所有变量添加
const/let声明,避免全局污染
内容的提问来源于stack exchange,提问作者kaliiiiiiiii
相关产品推荐
相关产品推荐

