修改来自Chrome扩展程序的HTTP响应


83

是否可以创建可修改HTTP响应正文的Chrome扩展程序?

我已经查看了Chrome扩展API,但没有找到任何相关方法。


1
一般来说,没有。请参阅https://code.google.com/p/chromium/issues/detail?id=104058。对于用例的子集,可以。您能否阐明为什么要编辑响应正文?
罗布W

好,谢谢。请写下来作为答案,我会接受的。
船长龙

如果您接受其他浏览器,则Firefox支持webRequest.filterResponseData()。不幸的是,这是仅Firefox的解决方案。
富兰克林于

Answers:


49

通常,您无法使用标准的Chrome扩展程序API更改HTTP请求的响应主体。

正在104104处请求此功能:WebRequest API:允许扩展来编辑响应正文。为问题加注星标以获取更新通知。

如果要编辑已知的响应主体XMLHttpRequest,请通过内容脚本注入代码,XMLHttpRequest以使用自定义(全功能)的默认构造函数覆盖默认构造函数,该自定义函数在触发真实事件之前会重写响应。确保您的XMLHttpRequest对象与Chrome的内置对象完全兼容XMLHttpRequest,否则AJAX繁重的网站将崩溃。

在其他情况下,可以使用chrome.webRequestchrome.declarativeWebRequestAPI将请求重定向到data:-URI。与XHR方法不同,您不会获得请求的原始内容。实际上,该请求永远不会到达服务器,因为重定向只能在发送实际请求之前完成。而且,如果您重定向main_frame请求,则用户将看到data:-URI而不是请求的URL。


1
我认为data:-URI的想法行不通。我只是尝试执行此操作,似乎CORS阻止了它。发出原始请求的页面最后说:“该请求已重定向到'data:text / json;,{...}',对于需要预检的跨域请求是不允许的。”

@Joe无法复制Chromium 39.0.2171.96
Rob W

1
@RobW,有哪些黑客或解决方案可以阻止URL更改为data:text...
Pacerier '17

1
@Pacerier确实没有令人满意的解决方案。在我的回答中,我已经提到了使用内容脚本替换内容的选项,但是除此之外,您不能在不引起URL更改的情况下“修改”响应。
Rob W

1
我尝试了这种解决方案。请注意,除了XMLHttpRequest外,您可能还需要覆盖fetch()。限制是浏览器对js / images / css的请求不会被拦截。
user861746

27

我刚刚发布了一个Devtools扩展程序,它就是这样:)

它被称为篡改,它基于mitmproxy,它使您可以查看当前选项卡发出的所有请求,对其进行修改并在下次刷新时提供修改后的版本。

这是一个相当早期的版本,但是应该与OS X和Windows兼容。让我知道这是否不适合您。

您可以在这里获得它http://dutzi.github.io/tamper/

如何运作

就像@Xan在下面评论的那样,该扩展通过Native Messaging与扩展mitmproxy的python脚本进行通信

该扩展名使用列出所有请求chrome.devtools.network.onRequestFinished

当您单击请求时,它使用请求对象的getContent()方法下载响应,然后将该响应发送到python脚本,该脚本将其保存在本地。

然后,它将在编辑器中打开文件(call用于OSX或subprocess.PopenWindows)。

python脚本使用mitmproxy来侦听通过该代理进行的所有通信,如果它检测到对已保存文件的请求,它将使用已保存的文件。

我使用了Chrome的代理API(特别是chrome.proxy.settings.set())将PAC设置为代理设置。该PAC文件将所有通信重定向到python脚本的代理。

关于mitmproxy的最大优点之一是它还可以修改HTTPs通信。所以你也有:)


有趣的解决方案,尽管它需要本地主机模块。
2014年

5
顺便说一句,如果您更好地解释这里使用的技术,那将有所帮助。
2014年

9
有趣的Devtools扩展!但是,似乎只能使用Tamper修改响应标头,而不能修改响应正文
Michael Trouw


1
我们可以以此来修改响应主体吗?
基兰

17

是。该chrome.debuggerAPI可以实现,该API授予对Chrome DevTools协议的扩展访问权限,该协议通过其Network API支持HTTP侦听和修改。

此解决方案是由有关Chrome问题487422的评论提出的:

对于目前想要可行的替代方法的任何人,您都可以chrome.debugger在后台/事件页面中使用它来附加到您要收听的特定标签上(或尽可能附加到所有标签上,尚未亲自测试过所有标签) ,然后使用调试协议的网络API。

唯一的问题是,除非用户在选项卡的视口顶部显示通常的黄色条,否则用户将其关闭chrome://flags

首先,将调试器附加到目标:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        // TODO
    });
});

接下来,发送Network.setRequestInterceptionEnabled命令,将启用对网络请求的拦截:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
    });
});

Chrome现在将开始发送Network.requestIntercepted事件。为他们添加一个监听器:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
    });

    chrome.debugger.onEvent.addListener((source, method, params) => {
        if(source.targetId === target.id && method === "Network.requestIntercepted") {
            // TODO
        }
    });
});

在侦听器中,params.request将是相应的Request对象。

发送回复Network.continueInterceptedRequest

  • 将所需的HTTP原始响应(包括HTTP状态行,标头等!)传递为base64编码rawResponse
  • 通过params.interceptionIdinterceptionId

请注意,我根本没有测试过任何一个。


看起来非常有前途,尽管我现在正在尝试(Chrome 60),但我丢失了某些东西还是仍然无法实现;该setRequestInterceptionEnabled方法似乎未包含在DevTools协议v1.2中,我无法找到将其附加到最新版本(树梢)的方法。
艾欧罗斯(Aioros)

1
我尝试了此解决方案,并且在一定程度上起作用了。如果要修改请求,此解决方案很好。如果要基于服务器返回的响应来修改响应,则无法进行。在这一点上没有任何回应。正如作者所说,您可以覆盖rawresponse字段。
user861746

1
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });因找不到“ Network.setRequestInterceptionEnabled”而失败”
Pacerier

1
@ MultiplyByZer0,确定设法使其正常工作。i.stack.imgur.com/n0Gff.png 但是,需要删除“ topbar”,即需要设置浏览器标志,然后重新启动浏览器,这意味着需要一种替代的实际解决方案。
Pacerier,

@Pacerier您说对了,这种解决方案并不理想,但是我不知道有什么更好的解决方案。另外,您已经注意到,此答案是不完整的,需要更新。希望我会尽快这样做。
MultiplyByZer0

12

就像@Rob w所说,我已经覆盖了XMLHttpRequest,这是修改任何站点中任何XHR请求的结果(类似于透明的修改代理):

var _open = XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function (method, URL) {
    var _onreadystatechange = this.onreadystatechange,
        _this = this;

    _this.onreadystatechange = function () {
        // catch only completed 'api/search/universal' requests
        if (_this.readyState === 4 && _this.status === 200 && ~URL.indexOf('api/search/universal')) {
            try {
                //////////////////////////////////////
                // THIS IS ACTIONS FOR YOUR REQUEST //
                //             EXAMPLE:             //
                //////////////////////////////////////
                var data = JSON.parse(_this.responseText); // {"fields": ["a","b"]}

                if (data.fields) {
                    data.fields.push('c','d');
                }

                // rewrite responseText
                Object.defineProperty(_this, 'responseText', {value: JSON.stringify(data)});
                /////////////// END //////////////////
            } catch (e) {}

            console.log('Caught! :)', method, URL/*, _this.responseText*/);
        }
        // call original callback
        if (_onreadystatechange) _onreadystatechange.apply(this, arguments);
    };

    // detect any onreadystatechange changing
    Object.defineProperty(this, "onreadystatechange", {
        get: function () {
            return _onreadystatechange;
        },
        set: function (value) {
            _onreadystatechange = value;
        }
    });

    return _open.apply(_this, arguments);
};

例如,Tampermonkey可以成功使用此代码在任何站点上进行任何修改:)


1
我用过您的代码,它记录了控制台上捕获的内容,但是它没有更改我的应用程序获得的响应(角度)。
安德烈·罗杰里·坎波斯(AndréRoggeri Campos),

2
@AndréRoggeriCampos我遇到了同样的事情。角采用了更新的response,而不是responseText,因此,所有你需要做的就是改变Object.defineProperty使用response代替
乔纳森Gawrych

非常感谢你 !它适用于我的chrome扩展程序!
Lancer.Yan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.