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

Firefox扩展开发:如何拦截eval、innerHTML等函数调用?

解决Firefox扩展拦截eval、innerHTML调用的方案

一、通过exportFunction替换原函数/属性

Firefox扩展的Content Script可以利用exportFunction API将自定义逻辑注入到页面上下文,绕过直接修改原生属性的限制:

1. 拦截eval

// 在Content Script中执行
// 获取页面上下文的原生eval
const originalEval = window.wrappedJSObject.eval;

// 自定义拦截逻辑
function interceptedEval(...args) {
  // 这里添加你的处理:记录调用、校验参数、阻止执行等
  console.log("拦截到eval调用,参数:", args);
  // 若需放行,调用原生eval:
  // return originalEval.apply(window.wrappedJSObject, args);
  throw new Error("eval调用已被拦截");
}

// 将拦截函数注入页面上下文,替换原生eval
exportFunction(interceptedEval, window.wrappedJSObject, { defineAs: "eval" });

2. 拦截innerHTML

针对元素的innerHTML属性,需要修改Element.prototype的属性描述符,结合exportFunction注入自定义的getter/setter:

// 获取页面上下文Element.prototype的原生innerHTML描述符
const originalInnerHTMLDesc = Object.getOwnPropertyDescriptor(
  window.wrappedJSObject.Element.prototype,
  "innerHTML"
);

// 自定义getter
function interceptedGetInnerHTML() {
  console.log("获取innerHTML,目标元素:", this);
  return originalInnerHTMLDesc.get.call(this);
}

// 自定义setter
function interceptedSetInnerHTML(value) {
  console.log("设置innerHTML,内容:", value, "目标元素:", this);
  // 若需放行,调用原生setter:
  // originalInnerHTMLDesc.set.call(this, value);
  throw new Error("innerHTML设置已被拦截");
}

// 构造新的属性描述符并注入页面上下文
const newInnerHTMLDesc = {
  get: exportFunction(
    interceptedGetInnerHTML,
    window.wrappedJSObject.Element.prototype
  ),
  set: exportFunction(
    interceptedSetInnerHTML,
    window.wrappedJSObject.Element.prototype
  ),
  configurable: true,
  enumerable: originalInnerHTMLDesc.enumerable
};

Object.defineProperty(
  window.wrappedJSObject.Element.prototype,
  "innerHTML",
  newInnerHTMLDesc
);

二、使用Proxy包装全局对象/元素原型

通过Proxy代理页面上下文的全局对象或元素原型,拦截属性访问与调用:

// 在Content Script中执行
const pageWindow = window.wrappedJSObject;

// 代理全局window对象,拦截eval
const proxiedWindow = new Proxy(pageWindow, {
  get(target, prop) {
    if (prop === "eval") {
      return function(...args) {
        console.log("拦截到eval调用:", args);
        // 放行逻辑:return target.eval(...args);
        throw new Error("eval调用已被拦截");
      };
    }
    return Reflect.get(target, prop);
  }
});

// 将代理后的window覆盖原页面的window对象
Object.defineProperty(pageWindow, "window", {
  value: proxiedWindow,
  configurable: true,
  writable: true
});

// 代理Element.prototype,拦截innerHTML
const proxiedElementProto = new Proxy(pageWindow.Element.prototype, {
  get(target, prop) {
    if (prop === "innerHTML") {
      return new Proxy(target[prop], {
        get(obj) {
          console.log("获取innerHTML:", obj);
          return obj;
        },
        set(obj, value) {
          console.log("设置innerHTML:", value);
          // 放行逻辑:target.innerHTML = value;
          return true;
        }
      });
    }
    return Reflect.get(target, prop);
  }
});

// 覆盖原Element.prototype
Object.defineProperty(pageWindow, "Element", {
  value: { prototype: proxiedElementProto },
  configurable: true,
  writable: true
});

注意事项

  • 若页面使用Function构造函数模拟eval(如new Function(code)),需额外拦截Function构造函数。
  • 类似insertAdjacentHTML这类可插入HTML的方法,也需要按相同逻辑拦截。
  • Manifest V3中需确保Content Script的匹配规则覆盖目标页面,如设置"all_frames": true、"match_about_blank": true等。
  • 所有注入到页面上下文的函数/对象,必须使用exportFunction或cloneInto处理,避免跨上下文安全报错。

内容的提问来源于stack exchange,提问作者Юрий Стражнов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 11:16:16