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

如何用Chrome扩展拦截或分析window.ethereum调用管控MetaMask

拦截MetaMask的window.ethereum调用实现方案

要在MetaMask之前捕获并拦截window.ethereum的所有调用,核心思路是利用Chrome扩展的内容脚本抢占注入时机,劫持页面的window.ethereum对象,通过代理或属性拦截实现调用控制。

步骤1:配置Chrome扩展清单(manifest.json)

必须让内容脚本在页面加载最早期注入,并运行在页面主上下文(而非隔离的内容脚本上下文),这样才能抢占MetaMask的注入时机:

{
  "manifest_version": 3,
  "name": "MetaMask调用拦截器",
  "version": "1.0",
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"],
      "run_at": "document_start",
      "world": "MAIN"
    }
  ]
}
  • run_at: document_start:确保脚本在页面DOM开始构建前执行,抢在MetaMask注入之前。
  • world: MAIN:让脚本运行在页面主上下文,直接访问和修改页面的window全局对象。

步骤2:编写内容脚本(content.js)劫持window.ethereum

通过Object.defineProperty拦截window.ethereum的getter和setter,保存MetaMask的原始对象,同时返回代理对象拦截所有调用:

// 拦截window.ethereum的属性读写
Object.defineProperty(window, 'ethereum', {
  get() {
    const originalEthereum = window.__originalEthereum;
    if (!originalEthereum) return null;

    // 用Proxy拦截所有方法调用和属性访问
    return new Proxy(originalEthereum, {
      get(target, prop) {
        // 处理方法调用
        if (typeof target[prop] === 'function') {
          return function(...args) {
            // 自定义判断逻辑,决定是否允许调用
            const isAllowed = checkPermission(prop, args);
            if (isAllowed) {
              return target[prop].apply(target, args);
            } else {
              console.log(`已拦截调用:ethereum.${prop}`);
              return Promise.reject(new Error('该调用已被拦截'));
            }
          };
        }
        // 非方法属性直接返回原始值
        return target[prop];
      }
    });
  },
  set(value) {
    // 保存MetaMask注入的原始ethereum对象
    window.__originalEthereum = value;
    return true;
  },
  configurable: true
});

// 自定义权限判断函数,可根据需求扩展
function checkPermission(methodName, args) {
  // 示例:拦截requestAccounts调用,弹出确认框
  if (methodName === 'requestAccounts') {
    return confirm(`是否允许当前网站请求MetaMask账户?`);
  }
  // 示例:拦截特定参数的eth_sendTransaction调用
  if (methodName === 'request' && args[0]?.method === 'eth_sendTransaction') {
    const tx = args[0].params[0];
    if (tx.value === '0x0') {
      return false; // 拦截无转账金额的交易请求
    }
  }
  // 其他调用默认允许
  return true;
}

关键注意事项

  • 异步方法处理:MetaMask的多数API返回Promise,拦截时需保持返回值类型一致,避免页面逻辑出错。
  • 事件监听拦截:如果需要拦截accountsChanged等事件的监听,可在Proxy的get方法中对addEventListener进行额外处理。
  • 兼容性测试:不同版本的MetaMask对window.ethereum的实现略有差异,需针对主流版本验证拦截逻辑。

内容的提问来源于stack exchange,提问作者Avishay Bikowsky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:54:22