Modifica le risposte HTTP da un’estensione di Chrome

È ansible creare un’estensione di Chrome che modifica i corpi di risposta HTTP?

Ho cercato nelle API dell’estensione di Chrome , ma non ho trovato nulla per farlo.

In generale, non è ansible modificare il corpo della risposta di una richiesta HTTP utilizzando le API di estensione standard di Chrome.

Questa funzione è richiesta al 104058: API WebRequest: consente all’estensione di modificare il corpo della risposta . Identifica il problema per ricevere notifiche sugli aggiornamenti.

Se si desidera modificare il corpo della risposta per una XMLHttpRequest nota, immettere il codice tramite uno script di contenuto per sovrascrivere il costruttore XMLHttpRequest predefinito con uno personalizzato (completo) che riscriva la risposta prima di triggersre l’evento reale. Assicurati che il tuo object XMLHttpRequest sia completamente compatibile con l’object XMLHttpRequest Chrome, altrimenti i siti pesanti di AJAX si interromperanno.

In altri casi, puoi utilizzare le API chrome.webRequest o chrome.declarativeWebRequest per redirect la richiesta a un data: -URI. A differenza dell’approccio XHR, non si otterrà il contenuto originale della richiesta. In realtà, la richiesta non colpirà mai il server perché il reindirizzamento può essere fatto solo prima che venga inviata la richiesta effettiva. E se reindirizzate una richiesta su main_frame , l’utente vedrà i data: -URI invece dell’URL richiesto.

Ho appena rilasciato un’estensione Devtools che fa proprio questo 🙂

Si chiama tamper, è basato su mitmproxy e consente di vedere tutte le richieste fatte dalla scheda corrente, modificarle e servire la versione modificata la prossima volta che si aggiorna.

È una versione piuttosto recente, ma dovrebbe essere compatibile con OS X e Windows. Fammi sapere se non funziona per te.

Puoi ottenerlo qui http://dutzi.github.io/tamper/

Come funziona

Come @Xan ha commentato di seguito, l’estensione comunica tramite Native Messaging con uno script python che estende mitmproxy .

L’estensione elenca tutte le richieste utilizzando chrome.devtools.network.onRequestFinished .

Quando fai clic sulle richieste, scarica la sua risposta utilizzando il metodo getContent() dell’object request e quindi invia tale risposta allo script python che lo salva localmente.

Quindi apre il file in un editor (utilizzando la call per OSX o subprocess.Popen per Windows).

Lo script python usa mitmproxy per ascoltare tutte le comunicazioni fatte attraverso quel proxy, se rileva una richiesta per un file che è stato salvato serve invece il file che è stato salvato.

Ho usato l’API proxy di Chrome (in particolare chrome.proxy.settings.set() ) per impostare un PAC come impostazione del proxy. Quel file PAC reindirizza tutte le comunicazioni al proxy dello script python.

Una delle cose più importanti di mitmproxy è che può anche modificare la comunicazione HTTP. Quindi lo hai anche 🙂

Sì. È ansible con l’API chrome.debugger , che garantisce l’accesso alle estensioni al protocollo Chrome DevTools , che supporta l’intercettazione e la modifica HTTP tramite la sua API di rete .

Questa soluzione è stata suggerita da un commento su Chrome Problema 487422 :

Per chiunque voglia un’alternativa che sia fattibile al momento, è ansible utilizzare chrome.debugger in una pagina di background / evento per collegarsi alla scheda specifica che si desidera ascoltare (o albind a tutte le tabs se è ansible, non averli testati tutti tabs personali), quindi utilizzare l’API di rete del protocollo di debug.

L’unico problema è che ci sarà la solita barra gialla nella parte superiore della finestra della scheda, a meno che l’utente non la spenga in chrome://flags .

Innanzitutto, collega un debugger alla destinazione:

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

Quindi, inviare il comando Network.setRequestInterceptionEnabled , che abiliterà l’intercettazione delle richieste di rete:

 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 inizierà ora a inviare eventi Network.requestIntercepted . Aggiungi un listener per loro:

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

Nel listener, params.request sarà l’object Request corrispondente.

Invia la risposta con Network.continueInterceptedRequest :

  • Passa una codifica base64 della tua risposta grezza HTTP desiderata ( inclusa riga di stato HTTP, intestazioni, ecc. ) Come rawResponse .
  • Passa params.interceptionId come interceptionId .

Nota che non ho provato nulla di tutto questo.

Come @Rob w ha detto, ho sovrascritto XMLHttpRequest e questo è un risultato per modificare qualsiasi richiesta XHR in qualsiasi sito (funziona come proxy di modifica trasparente):

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

per esempio questo codice può essere usato con successo da Tampermonkey per apportare modifiche su qualsiasi sito 🙂