Змінюйте відповіді HTTP із розширення Chrome


83

Чи можна створити розширення Chrome, яке змінює тіла відповіді HTTP?

Я заглянув у API розширень Chrome , але не знайшов для цього.


1
Загалом, ні. Див. Https://code.google.com/p/chromium/issues/detail?id=104058 . Для підмножини випадків використання - так. Чи можете ви пояснити, чому ви хочете редагувати тіла відповідей ?.
Роб W

добре, дякую. будь ласка, напишіть це як відповідь, і я прийму це.
капітан-дракон

Якщо ви приймаєте інші браузери, то Firefox підтримує webRequest.filterResponseData(). На жаль, це рішення лише для Firefox.
Франклін Ю

Відповіді:


49

Загалом, ви не можете змінити тіло відповіді на запит HTTP, використовуючи стандартні API розширення Chrome.

Цю функцію запитують за адресою 104058: WebRequest API: дозволити розширення редагувати тіло відповіді . Позначте цю зірочку, щоб отримувати сповіщення про оновлення.

Якщо ви хочете відредагувати тіло відповіді для відомого XMLHttpRequest, введіть код за допомогою сценарію вмісту, щоб замінити XMLHttpRequestконструктор за замовчуванням на власний (повнофункціональний), який переписує відповідь перед активацією реальної події. Переконайтеся, що ваш об’єкт XMLHttpRequest повністю відповідає вбудованому XMLHttpRequestоб’єкту Chrome, інакше сайти, важкі для AJAX, зламаються.

В інших випадках ви можете використовувати API chrome.webRequestабо chrome.declarativeWebRequestAPI для перенаправлення запиту на data:-URI. На відміну від підходу XHR, ви не отримаєте оригінальний вміст запиту. Насправді, запит ніколи не потрапить на сервер, оскільки перенаправлення може бути здійснено лише до того, як буде відправлений фактичний запит. І якщо ви перенаправите main_frameзапит, користувач побачить data:-URI замість запитуваної URL-адреси.


1
Не думаю, що дані: -Ідея УРІ працює. Я просто спробував це зробити, і, здається, CORS блокує це. Сторінка, що робить оригінальний запит, закінчується словами: "Запит було перенаправлено на 'data: text / json;, {...}', що заборонено для запитів про перехресне походження, які вимагають попередньої перевірки."
Джо

@Joe Не вдається відтворити в Chromium 39.0.2171.96
Роб W

1
@RobW, Які існують способи злому чи рішення, щоб зупинити зміну URL-адреси data:text...?
Pacerier

1
@Pacerier Насправді не існує задовільного рішення. У своїй відповіді я вже згадав варіант використання сценарію вмісту для заміни вмісту, але крім цього ви не можете "змінити" відповідь, не викликаючи зміни URL-адреси.
Роб W

1
Я спробував це рішення. Зверніть увагу, що вам може знадобитися перевизначення fetch () крім XMLHttpRequest. обмеження полягає в тому, що запити браузера до js / images / css не перехоплюються.
user861746

27

Я щойно випустив розширення Devtools, яке робить саме це :)

Це називається тампер, воно базується на mitmproxy і дозволяє переглядати всі запити, зроблені поточною вкладкою, змінювати їх та подавати змінену версію наступного разу, коли ви оновитеся.

Це досить рання версія, але вона повинна бути сумісна з OS X та Windows. Повідомте мене, якщо у вас це не працює.

Ви можете отримати його тут: http://dutzi.github.io/tamper/

Як це працює

Як @Xan коментував нижче, розширення спілкується за допомогою власних повідомлень за допомогою сценарію python, який розширює mitmproxy .

Розширення перераховує всі запити, які використовуються chrome.devtools.network.onRequestFinished.

Коли ви натискаєте один із запитів, він завантажує свою відповідь за допомогою getContent()методу об'єкта запиту , а потім надсилає цю відповідь скрипту python, який зберігає її локально.

Потім він відкриває файл у редакторі (використовуючи callдля OSX або subprocess.Popenдля Windows).

Сценарій python використовує mitmproxy для прослуховування всього спілкування, здійсненого через цей проксі, якщо він виявляє запит на файл, який було збережено, він обслуговує файл, який було збережено.

Я використовував проксі-API Chrome (зокрема chrome.proxy.settings.set()), щоб встановити PAC як налаштування проксі. Цей файл PAC перенаправляє всі зв’язки на проксі-скрипт python.

Однією з найкращих речей mitmproxy є те, що він також може змінювати зв'язок HTTP. Отже, у вас це теж є :)


Цікаве рішення, хоча воно вимагає модуля Native Host.
Xan

5
До речі, це допомогло б, якщо б ви краще пояснили техніку, яка використовується тут.
Xan

10
цікаве розширення Devtools! Однак, здається, можна змінити лише заголовки відповідей, а не тіло відповіді за допомогою Tamper.
Майкл Трув,

3
Проблема з установкою.
Дмитро Плешков

1
Чи можемо ми змінити тіло відповіді за допомогою цього?
Кіран,

18

Так. Це можливо завдяки chrome.debuggerAPI, який надає розширений доступ до протоколу Chrome DevTools , який підтримує перехоплення та модифікацію HTTP через свій мережевий 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:

  • Передайте кодування base64 вашої бажаної вихідної відповіді HTTP ( включаючи рядок стану HTTP, заголовки тощо! ) Як rawResponse.
  • Передайте params.interceptionIdяк interceptionId.

Зауважте, що я взагалі нічого з цього не тестував.


Виглядає дуже багатообіцяючим, хоча я намагаюся зараз (Chrome 60), або я щось пропускаю, або це все ще неможливо; setRequestInterceptionEnabledметод представляється не включені в v1.2 протоколу DevTools, і я не можу знайти спосіб , щоб прикріпити її з останньої (наконечник-з-дерева) версії замість.
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 Ви маєте рацію, що це рішення не є ідеальним, але я не знаю кращих. Крім того, як ви помітили, ця відповідь є неповною і потребує оновлення. Я сподіваюся це зробити найближчим часом.
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).
Андре Роггері Кампос,

2
@ AndréRoggeriCampos Я зіткнувся з тим самим. Angular використовує нове, responseа не responseText, тож все, що вам потрібно зробити, це змінити Object.defineProperty на використання responseзамість нього
Джонатан Гаврих

дуже тобі дякую ! це працює на моєму розширенні chrome!
Лансер. Ян
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.