Chrome 확장 프로그램에서 HTTP 응답 수정


83

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

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


1
일반적으로 아닙니다. https://code.google.com/p/chromium/issues/detail?id=104058을 참조 하세요 . 일부 사용 사례의 경우 그렇습니다. 응답 본문을 편집하려는 이유를 명확히 할 수 있습니까?.
Rob W

알았어 고마워. 답변으로 작성해 주시면 수락하겠습니다.
캡틴 드래곤

다른 브라우저를 허용하는 경우 Firefox는 webRequest.filterResponseData(). 불행히도 이것은 Firefox 전용 솔루션입니다.
Franklin Yu

답변:


49

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

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

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

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


1
데이터 : -URI 아이디어가 작동한다고 생각하지 않습니다. 나는 이것을 시도했고 CORS가 그것을 차단하는 것 같습니다. 원래 요청을 작성하는 페이지는 "요청이 'data : text / json;, {...}'으로 리디렉션되었습니다.이 요청은 프리 플라이트가 필요한 교차 출처 요청에 허용되지 않습니다."
Joe

@Joe는 Chromium 39.0.2171.96에서 재현 할 수 없습니다
Rob W

1
@RobW, URL이 변경되는 것을 막는 몇 가지 해킹 또는 솔루션 은 무엇입니까 data:text...?
Pacerier

1
@Pacerier 정말 만족스러운 해결책은 없습니다. 내 대답에서 이미 콘텐츠 스크립트를 사용하여 콘텐츠를 대체하는 옵션에 대해 언급했지만 URL을 변경하지 않고는 응답을 "수정"할 수 없습니다.
Rob W

1
이 솔루션을 시도했습니다. XMLHttpRequest 외에 fetch ()를 재정의해야 할 수도 있습니다. 제한은 js / images / css에 대한 브라우저의 요청이 가로 채지 않는다는 것입니다.
user861746

27

방금 그 기능을 수행하는 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 통신을 수정할 수도 있다는 것입니다. 그래서 당신은 또한 :)


흥미로운 솔루션이지만 네이티브 호스트 모듈이 필요합니다.
Xan 2014 년

5
그런데 여기서 사용 된 기술을 더 잘 설명하면 도움이 될 것입니다.
Xan 2014 년

9
흥미로운 Devtools 확장! 그러나 Tamper로 응답 본문 이 아닌 응답 헤더 만 수정할 수있는 것 같습니다 .
Michael Trouw

3
설치에 문제가 있습니다.
Dmitry Pleshkov

1
이것으로 응답 본문을 수정할 수 있습니까?
Kiran

17

예. 네트워크 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.

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


매우 유망 해 보이지만 지금 시도하고 있고 (Chrome 60) 뭔가 빠졌거나 여전히 가능하지 않습니다. 이 setRequestInterceptionEnabled방법은 DevTools 프로토콜 v1.2에 포함되어 있지 않은 것 같습니다. 대신 최신 (Tip-of-Tree) 버전으로 연결하는 방법을 찾을 수 없습니다.
Aioros

1
나는이 해결책을 시도했고 어느 정도 효과가 있었다. 요청을 수정하고 싶다면이 솔루션이 좋습니다. 서버에서 반환 된 응답을 기반으로 응답을 수정하려면 방법이 없습니다. 그 시점에서 응답이 없습니다. coz의 저자가 말한 것처럼 rawresponse 필드를 덮어 쓸 수 있습니다.
user861746

1
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });'Network.setRequestInterceptionEnabled'를 찾을 수 없음 '으로 실패 함'
Pacerier

1
@ MultiplyByZer0, Ok가 작동하도록 관리했습니다. i.stack.imgur.com/n0Gff.png 그러나 '
Pacerier

@Pacerier이 솔루션이 이상적이지 않다는 말이 맞지만 더 좋은 솔루션은 없습니다. 또한 아시다시피이 답변은 불완전하며 업데이트가 필요합니다. 곧 그렇게하겠습니다.
MultiplyByZer0

13

@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
나는 당신의 코드를 사용했고 콘솔에 잡힌 것을 기록했지만 내 응용 프로그램이 (Angular)받은 응답을 변경하지 않았습니다.
André Roggeri Campos

2
@ AndréRoggeriCampos 나도 같은 일을 만났습니다. 각도 용도 새로운 response보다는은 responseText, 당신이해야 할 모든 그래서 사용하는 Object.defineProperty을 변경할 수 있습니다 response대신
조나단 Gawrych

대단히 감사합니다! 내 크롬 확장 프로그램에서 작동합니다!
Lancer.Yan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.