Bir Chrome uzantısından HTTP yanıtlarını değiştirin


83

HTTP yanıt gövdelerini değiştiren bir Chrome uzantısı oluşturmak mümkün müdür?

Chrome Uzantı API'lerine baktım , ancak bunu yapacak bir şey bulamadım.


1
Genel olarak hayır. Https://code.google.com/p/chromium/issues/detail?id=104058 adresine bakın . Kullanım durumlarının bir alt kümesi için, evet. Yanıt gövdelerini neden düzenlemek istediğinizi açıklayabilir misiniz?
Rob W

tamam teşekkürler. lütfen bir cevap olarak yazın ve ben bunu kabul edeceğim
kaptan ejderha

Diğer tarayıcıları kabul ediyorsanız, Firefox destekler webRequest.filterResponseData(). Ne yazık ki bu yalnızca Firefox'a özgü bir çözümdür.
Franklin Yu

Yanıtlar:


49

Genel olarak, olamaz standart Chrome uzantısı API'leri kullanarak bir HTTP isteğinin yanıt gövdesini değiştirin.

Bu özellik 104058'de talep edilmektedir: WebRequest API: uzantının yanıt gövdesini düzenlemesine izin verin . Güncellemelerden haberdar olmak için soruna yıldız ekleyin.

Düzenlemeye bilinen için yanıt gövdesini istiyorsanız XMLHttpRequest, bir İçerik komut yoluyla enjekte kod varsayılan geçersiz kılmak için XMLHttpRequestözel bir alan kurucu gerçek olayı tetiklemeden önce tepkisini yeniden yazar birini (tam özellikli). XMLHttpRequest nesnenizin Chrome'un yerleşik nesnesiyle tamamen uyumlu olduğundan emin olun XMLHttpRequest, aksi takdirde AJAX ağırlıklı siteler bozulacaktır.

Diğer durumlarda, isteği bir -URI'ye yeniden yönlendirmek için chrome.webRequestveya chrome.declarativeWebRequestAPI'lerini kullanabilirsiniz data:. XHR yaklaşımının aksine, isteğin orijinal içeriğini alamazsınız. Aslında, istek sunucuya hiçbir zaman isabet etmez çünkü yeniden yönlendirme yalnızca gerçek istek gönderilmeden önce yapılabilir. Ve bir main_frameisteği yeniden yönlendirirseniz , kullanıcı data:istenen URL yerine -URI'yi görecektir.


1
Verilerin olduğunu sanmıyorum: -URI fikri işe yarıyor. Bunu yapmaya çalıştım ve görünen o ki CORS engelliyor. Orijinal isteği yapan sayfada "İstek, ön kontrol gerektiren çapraz kaynak isteklerinde izin verilmeyen 'data: text / json;, {...}' öğesine yeniden yönlendirildi."
Joe

@Joe Chromium'da çoğaltılamıyor 39.0.2171.96
Rob W

1
@RobW, URL'nin değişmesini engellemek için bazı hackler veya çözümlerdata:text... nelerdir?
Pacerier

1
@Pacerier Gerçekten tatmin edici bir çözüm yok. Cevabımda, içeriği değiştirmek için bir içerik komut dosyası kullanma seçeneğinden daha önce bahsetmiştim, ancak bunun dışında, URL'nin değişmesine neden olmadan yanıtı "değiştiremezsiniz".
Rob W

1
Bu çözümü denedim. XMLHttpRequest'in yanı sıra fetch () öğesini geçersiz kılmanız gerekebileceğini unutmayın. sınırlama, tarayıcının js / images / css isteklerinin yakalanmamasıdır.
user861746

27

Sadece bunu yapan bir Devtools eklentisi yayınladım :)

Buna kurcalama denir, mitmproxy'ye dayanır ve mevcut sekme tarafından yapılan tüm istekleri görmenize, bunları değiştirmenize ve bir sonraki yenilemenizde değiştirilmiş sürümü sunmanıza olanak tanır.

Oldukça erken bir sürüm ama OS X ve Windows ile uyumlu olması gerekiyor. Senin için işe yaramazsa bana haber ver.

Buradan alabilirsiniz http://dutzi.github.io/tamper/

Bu nasıl çalışır

@Xan'ın aşağıda yorumladığı gibi, uzantı, mitmproxy'yi genişleten bir python betiği ile Yerel Mesajlaşma aracılığıyla iletişim kurar .

Uzantı kullanan tüm istekleri listeler chrome.devtools.network.onRequestFinished.

İsteklere tıkladığınızda, yanıtını istek nesnesinin getContent()yöntemini kullanarak indirir ve ardından bu yanıtı yerel olarak kaydeden python betiğine gönderir.

Daha sonra dosyayı bir düzenleyicide açar ( callOSX veya subprocess.PopenWindows için kullanarak ).

Python betiği, o proxy aracılığıyla yapılan tüm iletişimi dinlemek için mitmproxy kullanır; kaydedilen bir dosya için bir istek algılarsa, bunun yerine kaydedilen dosyaya hizmet eder.

chrome.proxy.settings.set()Proxy ayarı olarak bir PAC ayarlamak için Chrome'un proxy API'sini (özellikle ) kullandım. Bu PAC dosyası, tüm iletişimi python betiğinin proxy'sine yönlendirir.

Mitmproxy ile ilgili en büyük şeylerden biri, HTTPs iletişimini de değiştirebilmesidir. Yani buna da sahipsiniz :)


İlginç bir çözüm, ancak bir Yerel Ana Bilgisayar modülü gerektiriyor.
Xan

5
Bu arada, burada kullanılan tekniği daha iyi açıklarsanız yardımcı olur.
Xan

10
ilginç Devtools uzantısı! Bununla birlikte , Tamper ile yanıt gövdesinin değil, yalnızca yanıt başlıklarının değiştirilebileceği görülmektedir .
Michael Trouw

3
Kurulumla ilgili sorun.
Dmitry Pleshkov

1
Yanıt gövdesini bununla değiştirebilir miyiz?
Kiran

17

Evet. Ağ API'si aracılığıyla HTTP müdahalesini ve değiştirmeyi destekleyen Chrome DevTools Protokolünechrome.debugger uzantı erişimi sağlayan API ile mümkündür .

Bu çözüm, Chrome Issue 487422'de bir yorum tarafından önerildi :

Şu anda yapılabilen bir alternatif isteyen herkes chrome.debuggeriçin, dinlemek istediğiniz belirli sekmeye eklemek için bir arka plan / olay sayfasında kullanabilirsiniz (veya mümkünse tüm sekmelere iliştirebilirsiniz, tüm sekmeleri kişisel olarak test etmediniz) , ardından hata ayıklama protokolünün ağ API'sini kullanın.

Bununla ilgili tek sorun, kullanıcı onu kapatmadıkça sekme görünümünün üst kısmında olağan sarı çubuğun olacağıdır chrome://flags.

İlk olarak, hedefe bir hata ayıklayıcı ekleyin:

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

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

Ardından, Network.setRequestInterceptionEnabledağ isteklerinin engellenmesini sağlayacak komutu gönderin :

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 şimdi Network.requestInterceptedetkinlik göndermeye başlayacak . Onlar için bir dinleyici ekleyin:

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
        }
    });
});

Dinleyicide params.requestkarşılık gelen Requestnesne olacaktır.

Yanıtı şununla gönderin Network.continueInterceptedRequest:

  • İstediğiniz HTTP ham yanıtının ( HTTP durum satırı, başlıklar vb. Dahil! ) Base64 kodlamasını olarak iletin rawResponse.
  • Geçiş params.interceptionIdolarak interceptionId.

Bunların hiçbirini test etmediğimi unutmayın.


Çok umut verici görünüyor, ancak şimdi deniyor olsam da (Chrome 60) ve ya bir şeyi kaçırıyorum ya da hala mümkün değil; setRequestInterceptionEnabledyöntem DevTools protokol v1.2 dahil edilmez görünüyor ve bunun yerine son (uç-of-ağacının) sürümde eklemek için bir yol bulmak mümkün değil.
Aioros

1
Bu çözümü denedim ve bir dereceye kadar işe yaradı. İsteği değiştirmek istiyorsanız, bu çözüm iyidir. Yanıtı, sunucu tarafından döndürülen yanıta göre değiştirmek istiyorsanız, hiçbir yol yoktur. o noktada yanıt yok. yazarın söylediği gibi ham yanıt alanının üzerine yazabilirsiniz.
user861746

1
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });'Network.setRequestInterceptionEnabled' bulunamadı 'ile başarısız
Pacerier

1
@ MultiplyByZer0, Tamam onu ​​çalıştırmayı başardı. i.stack.imgur.com/n0Gff.png Ancak, 'üst çubuğu' kaldırma ihtiyacı, yani tarayıcı bayrağını ayarlama ve ardından tarayıcının yeniden başlatılması ihtiyacı, alternatif bir gerçek çözüme ihtiyaç olduğu anlamına gelir.
Pacerier

@Pacerier Bu çözümün ideal olmadığı konusunda haklısın, ama daha iyisini bilmiyorum. Ayrıca, fark ettiğiniz gibi, bu cevap eksik ve güncellenmesi gerekiyor. Umarım bunu yakında yapacağım.
MultiplyByZer0

13

@Rob w'nin söylediği gibi, geçersiz kıldım XMLHttpRequestve bu, herhangi bir sitedeki herhangi bir XHR talebinin değiştirilmesinin bir sonucudur (şeffaf modifikasyon proxy'si gibi çalışır):

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);
};

örneğin bu kod, herhangi bir sitede herhangi bir değişiklik yapmak için Tampermonkey tarafından başarıyla kullanılabilir :)


1
Kodunuzu kullandım ve yakalananları konsola kaydetti, ancak uygulamamın aldığı yanıtı değiştirmedi (Angular)
André Roggeri Campos

2
@ AndréRoggeriCampos Ben de aynı şeyle karşılaştım. Angular responseyerine yeni responseTextolanı kullanıyor, bu yüzden tek yapmanız gereken responsebunun yerine Object.defineProperty'yi değiştirmek
Jonathan Gawrych

çok teşekkür ederim ! Chrome uzantım üzerinde çalışıyor!
Lancer.Yan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.