[google-chrome-extension] Chrome 확장 프로그램에서 HTTP 응답 수정

HTTP 응답 본문을 수정하는 Chrome 확장 프로그램을 만들 수 있습니까?

Chrome Extension API를 살펴 봤지만이 작업을 수행 할 수있는 항목을 찾지 못했습니다.



답변

일반적으로 표준 Chrome 확장 API를 사용하여 HTTP 요청의 응답 본문을 변경할 수 없습니다 .

이 기능은 104058 : WebRequest API : 확장이 응답 본문을 편집 할 수 있도록 허용합니다 . 업데이트 알림을 받으려면 문제에 별표를 표시하십시오.

편집 알려진에 대한 응답 본문하려면 XMLHttpRequest, 콘텐츠 스크립트를 통해 분사 코드를 기본 재정의하는 XMLHttpRequest사용자 정의와 생성자를 실제 이벤트를 트리거하기 전에 응답을 다시 쓰는 일을 (전체는 기능). XMLHttpRequest 객체가 Chrome의 내장 XMLHttpRequest객체 와 완전히 호환되는지 확인하십시오 . 그렇지 않으면 AJAX가 많은 사이트가 중단됩니다.

다른 경우에는 chrome.webRequest또는 chrome.declarativeWebRequestAPI를 사용 하여 요청을 data:-URI 로 리디렉션 할 수 있습니다 . XHR 방식과 달리 요청의 원래 내용을 얻지 못합니다. 실제로 리디렉션은 실제 요청이 전송되기 전에 만 수행 될 수 있기 때문에 요청이 서버에 도달하지 않습니다. main_frame요청 을 리디렉션 하면 사용자 data:에게 요청 된 URL 대신 -URI 가 표시됩니다 .


답변

방금 그 기능을 수행하는 Devtools 확장을 출시했습니다. 🙂

탬퍼라고하며 mitmproxy를 기반으로 하며 현재 탭에서 만든 모든 요청을보고 수정하고 다음에 새로 고칠 때 수정 된 버전을 제공 할 수 있습니다.

꽤 초기 버전이지만 OS X 및 Windows와 호환되어야합니다. 작동하지 않으면 알려주세요.

여기 http://dutzi.github.io/tamper/에서 얻을 수 있습니다.

작동 원리

@Xan이 아래에 언급했듯이 확장은 기본 메시징을 통해 mitmproxy 를 확장하는 python 스크립트와 통신 합니다.

확장 프로그램은 chrome.devtools.network.onRequestFinished.

요청을 클릭하면 요청 객체의 getContent()메서드를 사용하여 응답을 다운로드 한 다음 해당 응답을 로컬에 저장하는 python 스크립트로 보냅니다.

그런 다음 편집기에서 파일을 엽니 다 ( callOSX 또는 subprocess.PopenWindows 용).

python 스크립트는 mitmproxy를 사용하여 해당 프록시를 통해 이루어진 모든 통신을 수신합니다. 저장된 파일에 대한 요청을 감지하면 대신 저장된 파일을 제공합니다.

Chrome의 프록시 API (특히 chrome.proxy.settings.set())를 사용하여 PAC를 프록시 설정으로 설정했습니다. 이 PAC 파일은 모든 통신을 python 스크립트의 프록시로 리디렉션합니다.

mitmproxy의 가장 큰 장점 중 하나는 HTTP 통신을 수정할 수도 있다는 것입니다. 그래서 당신은 또한 🙂


답변

예. 네트워크 API를 통해 HTTP 가로 채기와 수정을 지원 chrome.debugger하는 Chrome DevTools 프로토콜에 대한 확장 액세스 권한을 부여 하는 API 로 가능 합니다 .

이 솔루션은 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 원시 응답의 인코딩 base64로 통과 HTTP 상태 라인, 헤더 등! 포함 등을) rawResponse.
  • 패스 params.interceptionIdinterceptionId.

나는 이것 중 어느 것도 전혀 테스트하지 않았습니다.


답변

@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가 성공적으로 사용할 수 있습니다. 🙂


답변