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

如何在WebView中永久覆盖JS DOM API并拦截指定JS函数防篡改?

嘿,这个问题问到点子上了——我刚好在做类似的浏览器安全拦截功能,给你梳理下可行的方案和注意点:

核心问题解答:直接覆盖后能否被delete移除?

默认情况下,是的。window上的原生属性(比如fetch、XMLHttpRequest、postMessage)默认的configurable特性是true,这意味着它们可以被删除、重新配置。举个例子:

// 你先覆盖fetch
window.fetch = (...args) => { /* 你的拦截逻辑 */ };
// 后续代码可以直接删除
delete window.fetch;
// 此时fetch会恢复成原生版本

所以直接覆盖肯定不安全,得用更稳妥的方式锁定这些属性。


方案1:用Object.defineProperty锁定拦截后的属性

这是JS层面最常用的可靠方法——通过重新定义属性,把configurable和writable都设为false,这样既不能删除,也不能重新赋值。

拦截fetch的示例:

const originalFetch = window.fetch;
Object.defineProperty(window, 'fetch', {
  value: function(...args) {
    // 这里加你的拦截判断:比如检查请求域名、是否来自目标iframe
    const [url] = args;
    if (url.includes('https://blocked-domain.com')) {
      console.log('Fetch请求被拦截');
      return Promise.reject(new Error('Blocked by custom browser'));
    }
    // 符合条件就调用原生fetch
    return originalFetch.apply(this, args);
  },
  writable: false,       // 禁止重新赋值
  configurable: false,    // 禁止删除/重新配置
  enumerable: true        // 保持原属性的可枚举性
});

拦截XMLHttpRequest的示例:

XHR是构造函数,我们可以拦截它的open方法来检查请求:

const originalXHR = XMLHttpRequest;
Object.defineProperty(window, 'XMLHttpRequest', {
  value: function() {
    const xhr = new originalXHR();
    // 拦截open方法
    const originalOpen = xhr.open;
    xhr.open = function(method, url) {
      if (url.includes('https://blocked-domain.com')) {
        throw new Error('XHR请求被拦截');
      }
      return originalOpen.apply(this, arguments);
    };
    return xhr;
  },
  writable: false,
  configurable: false
});

拦截postMessage的示例:

同样锁定window.postMessage,检查消息目标或来源:

const originalPostMessage = window.postMessage;
Object.defineProperty(window, 'postMessage', {
  value: function(message, targetOrigin, transfer) {
    // 拦截逻辑:比如检查目标域名是否是要阻止的
    if (targetOrigin === 'https://blocked-domain.com') {
      console.log('postMessage被拦截');
      return;
    }
    return originalPostMessage.apply(this, arguments);
  },
  writable: false,
  configurable: false
});

设置完之后,delete window.fetch会返回false(严格模式下直接抛错),也无法重新赋值这些属性。


方案2:用Object.freeze/Object.seal强化锁定

如果想更彻底,可以用Object.freeze冻结拦截后的属性——它会把属性设为不可写、不可配置、不可枚举(保持原枚举性的话还是用defineProperty更灵活)。不过注意,冻结的是属性值本身,比如你覆盖的函数对象,冻结后它的内部属性也不能修改:

// 先覆盖,再冻结
window.fetch = (...args) => { /* 拦截逻辑 */ };
Object.freeze(window.fetch);

或者用Object.seal,它允许修改属性值但禁止删除和重新配置,适合需要后续调整拦截逻辑的场景。


方案3:原生代码拦截(最可靠,适合自定义浏览器)

JS层面的拦截始终存在被绕过的可能(比如页面提前备份了原生对象),所以如果是开发自定义浏览器(比如安卓Chrome衍生版、WebView应用),原生层面的拦截才是终极方案。

安卓Chrome/WebView的实现方式:

  1. 拦截网络请求(fetch/XHR):
    用WebViewClient的shouldInterceptRequest方法,能拦截所有网络请求,直接在原生层拒绝目标域名的请求:

    webView.setWebViewClient(new WebViewClient() {
      @Override
      public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        String url = request.getUrl().toString();
        if (url.contains("blocked-domain.com")) {
          // 返回空响应,阻止请求
          return new WebResourceResponse(null, null, null);
        }
        return super.shouldInterceptRequest(view, request);
      }
    });
    
  2. 拦截postMessage:
    可以通过addJavascriptInterface注入原生检查逻辑,或者在页面加载最早期(onPageStarted时机)注入你的JS拦截代码,确保在页面所有JS执行前生效。如果是浏览器扩展,还可以用chrome.webRequest API拦截,权限更高更稳定。


关键注意点
  • 注入时机要早:不管是JS还是原生注入,一定要在页面的所有JS代码执行前加载你的拦截逻辑,否则页面可能已经备份了原生对象,绕过你的拦截。
  • iframe要覆盖到:如果要拦截特定iframe,确保你的拦截代码能注入到所有iframe中(比如浏览器扩展设置all_frames: true,WebView开启跨域权限并注入代码到iframe)。

内容的提问来源于stack exchange,提问作者Gregory Magarshak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:51:19