HTTP MITMProxy — помощник в разработке и тестировании

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Наверное каждый разработчик и QA-инженер, в рабочем процессе сталкивался с необходимостью подмены отправляемых/принимаемых данных. Когда эта задача касается данных, гуляющих между клиентом и сервером, особых проблем она не приносит. Запрос можно модифицировать и отправить ручками, к примеру через Postman, а для модификации ответа можно использовать инструменты вроде Burp Suite, Charles и т.д., но что делать если целевой запрос отправляется с сервера?

Рассмотрим простую схему процесса оплаты:

  1. Пользователь заполняет платежные данные

  2. Фронт отправляет их на endpoint API

  3. Бэкэнд общается с другими системами по HTTP, выполняет различные действия и отправляет ответ на фронт

  4. Фронт отображает сообщение для клиента

Предположим, перед QA стоит задача протестировать фикс плавающего, крайне редко встречающегося бага, возникающего из-за получения бэкэндом некорректных данных от сторонней системы.

На моей практике такие ситуации возникали не раз и всегда вовлекали в процесс тестирования бэкэнд специалиста, который далее выкручивался как мог. Чаще всего решением проблемы служил какой-то временный костыль в коде, который добавлялся для проведения теста и удалялся сразу после этого.

Встречались ситуации и сложнее, когда данные нужно было подменить не в одном, а сразу в серии запросов, каждый последующий из которой формировался на основе ответов предыдущих.

Рассмотрим простую схему процесса бронирования:

  1. Пользователь заполняет данные о пассажирах

  2. Фронт отправляет их на endpoint API

  3. Бэкэнд запрашивает у поставщика актуальную информацию о рейсе

  4. Далее формирует запрос на бронирование с учетом полученной ранее актуальной информации о рейсе и отправляет ответ на фронт

  5. Фронт отображает сообщение для клиента

В таком случае уже не получится обойтись простым моком ответа конкретного запроса, т.к. часть запросов из серии могут быть зависимы друг от друга. К тому же, для полноценного тестирования, скорей всего нужно будет сделать несколько итераций, с разными значениями. Возможно будет недостаточно одного деплоя и код придётся выкладывать в тестовое окружение несколько раз. Как итог - количество костылей и их сложность растет, а время разработчика расходуется не оптимально.

Если вы пишете на PHP и вам знакома эта боль, добро пожаловать под кат.


Дальнейшая часть статьи является мануалом к библиотеке https://github.com/Chetkov/http-client-mitmproxy, которую предлагаю в качестве решения описанной выше проблемы.

Библиотека предоставляет набор инструментов для клиентской и серверной стороны: 

  1. Консольный клиент для для пользователя

  2. Декоратор над \Psr\Http\Client\ClientInterface, который через канал коммуникации общается с консольным клиентом и дает возможность модифицировать запросы и ответы в интерактивном режиме.

Для наглядности я подготовил demo-проект https://github.com/Chetkov/http-client-mitmproxy-example. Сильно изощряться не стал, т.к. считаю что это было бы избыточно, но для демонстрации работы http-client-mitmproxy его вполне достаточно.

В нем доступны:

  1. artisan команда currency-rates:show {code} (возвращает список курсов валют)

  2. endpoint /currency-rates (возвращает список курсов валют)

  3. endpoint /currency-rates/{code} (возвращает курс конкретной валюты)

  4. endpoint /calculate (делает несколько запросов к currency-rates/{code}, получает курсы и рассчитывает суммы в разных валютах, на основе суммы в рублях)

Установка http-client-mitmproxy

composer require v.chetkov/http-client-mitmproxy

Настройка http-client-mitmproxy

Общее

В данный момент, канал коммуникации \Chetkov\HttpClientMitmproxy\Communication\CommunicationChannelInterface между декоратором и пользовательским клиентом, реализован на базе Redis, поэтому на клиентской и серверной стороне, в конфиге необходимо указать идентичные данные для подключения к нему:

<?php

declare(strict_types=1);

return [
   // For redis based communication channels
   'redis' => [
       'host' => 'redis-host',
       'port' => 6379,
       'timeout' => 0,
   ],
];

Настройка бэкэнда

Также, на стороне бэкэнда, для нужного окружения, в случае обнаружения ProxyUID, в качестве реализации \Psr\Http\Client\ClientInterface необходимо использовать декоратор, поставляемый библиотекой:

<?php 

// ...

$this->app->bind(ClientInterface::class, function (Container $container) {
    $client = new Client(['allow_redirects' => true]);


    if ($proxyUid = ProxyUID::detect()) {
        $config = require dirname(__DIR__, 2) . '/config/mitmproxy.config.php';
        $mitmproxyFactory = new DefaultFactory($config);


        $client = $mitmproxyFactory->createHttpClientDecorator($proxyUid, $client);
    }

    return $client;
});

Использование

Запускаем PHP web-сервер

cd http-client-mitmproxy-example
php -S localhost:8000 -t public/

Запускаем консольный клиент

С помощью опций можно задать:

  • --config путь к файлу конфигурации

  • --temp-dir путь к временной директории (должна быть доступна для записи)

  • --app-mode режим работы целевого приложения (cli, web)

  • --format предпочитаемый формат для редактирования данных (yaml, json, php)

  • --editor предпочитаемый редактор (nano, vim, gedit)

В случае отсутствия в списке опций последних трех (app-mode, format, editor), клиент запросит их в интерактивном режиме

Затем будет выведено сообщение с дальнейшими инструкциями.

Для WEB mode:

Для CLI mode:

Запускаем целевое приложение

Следуя предложенным инструкциям выполним artisan команду

export MITM_PROXY_UID=0ff6b1f2a9ebc702ea9b84b0fe019f6b &&
php artisan currency-rates:show USD

И подменим дату в отправляемом к API центробанка запросе на 2010 год

Затем согласимся с редактированием полученного от центробанка ответа

И изменим название доллара США на "Зелёный"

Затем откажемся от продолжения редактирования других полей и всего ответа целиком и увидим сообщение о завершении текущей сессии

Теперь клиент ожидает новых соединений (т.е. процессов, запущенных с его ProxyUID), а запущенная artisan команда думает, что USD на сайте центробанка называется “Зелёный” и его актуальный курс “30”

Думаю, на этом статью можно закончить. Спасибо за внимание.

Если после прочтения у вас возникли вопросы или предложения, я с радостью готов обсудить их в комментариях.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Считаете
25% Безусловно, полезная штука 1
25% Затрудняюсь ответить 1
50% Абсолютно бесполезная вещь 2
Проголосовали 4 пользователя. Воздержавшихся нет.
Источник: https://habr.com/ru/post/717882/


Интересные статьи

Интересные статьи

Что бы вы сказали, если бы вам потребовалось срезать косты вашей команды разработки в два раза? А если бы пришел босс и потребовал делать в два раза больше той же командой? Обычно интуиция нас подводи...
Если открыть вакансии QA, можно увидеть огромный разброс открытых позиций — от младшего тестировщика до ведущего, а иной раз и до главного. Часто слышу вопрос, чем должен обладать тестировщик уровня с...
Ищете вдохновения в области тестирования программного обеспечения? Вашему вниманию список материалов от одних из самых известных экспертов в этой области. Насладитесь 14 ...
Ситуацию с использованием кодов ответов HTTP можно заносить в палату мер и весов: вот что происходит, когда благие намерения разработчиков спецификации сталкиваются с жестокой реальностью...
Автор материала, перевод которого мы публикуем, говорит, что в мире разработки программного обеспечения «архитектурным проектированием» можно назвать процесс конструирования приложения, в ходе ко...