You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 04:10:29