mitmproxy — консольный firebug
Опубликовано 16.05.2013
Firebug — отличная штука, когда дело касается анализа запросов в конкретном браузере, но часто приходится отлаживать не связанные ни с каким браузером клиент-серверные приложения, общающиеся с сервером по протоколу HTTP. Я пишу тесты HTTP API на python, и часто ощущается необходимость удобного просмотра трафика от меня к серверу. Для админов и веб-разработчиков может быть актуальным мониторинг трафика от nginx к HTTP-бэкенду.
Общепринятые инструменты, прослушивающие трафик (tcpdump, ngrep, tshark), либо не поддерживают http в полной мере (хочется, как минимум, нормальное отображение заголовков по одному на строке и отображение сжатого gzip или deflate контента), либо в силу своей универсальности слишком сложны в настройке и использовании в контексте конкретной задачи (wireshark). Да и не всегда есть возможность перевести интерфейс в состояние promisc, чтобы получать трафик, хотя бы по причине недостатка прав.
Установка nginx, squid, 3proxy или любого другого известного прокси-сервера также связана с многими трудностями, да и не везде можно нормально настроить полное журналирование заголовков запросов и ответов.
Идеальным решением был бы сервис, работающий как HTTP-прокси, способный работать с правами пользователя, не требующий множества действий для конфигурации логов и запуска, отображающий куда-нибудь заголовки запросов и ответов в человекочитаемом формате, а при необходимости — и тела запросов и ответов.
После недолгих поисков нашел инструмент, идеально соответствующий таким требованиям: mitmproxy — прокси-сервер, написанный на Python, умеющий перехватывать HTTP и HTTPS, менять трафик на лету, воспроизводить записанный трафик, декодировать и отображать основные типы документов. Под катом — подробный обзор.
Для его запуска необходимо всего ничего:
- поставить mitmproxy одним из способов:
sudo aptitude install mitmproxy
или
easy_install mitmproxy
или
pip install mitmproxy
или
wget -O - http://mitmproxy.org/download/mitmproxy-0.8.1.tar.gz |tar -xf - cd mitmproxy-0.8.1 python setup.py build python setup.py install
Последние три годятся даже в случае, когда нет root’а на машине и окружение python установлено локально, например, по этому руководству;
- запустить в режиме прокси-сервера:
mitmproxy -p 3128 -a 127.0.0.1
Если все зависимости установлены, появится пустое окно, выйти из него можно по кнопке Q или Ctrl+C, а по знаку вопроса «?» можно получить справку;
- указать своему приложению использовать прокси для HTTP и HTTPS, например, с помощью переменных окружения:
$ HTTP_PROXY=http://127.0.0.1:3128 HTTPS_PROXY=http://127.0.0.1:3128 python testproxy.py
Теперь, если все сделано правильно, в окне mitmproxy появится лог запросов.
Чтобы не быть голословным, приведу пример небольшого скрипта с микротестом сервиса отладки запросов httpbin.com. Для его запуска требуется установленная библиотека requests. Код неидеален, т.к. его цель — не протестировать весь httpbin.com, а просто проиллюстрировать работу прокси-сервера:
После того, как я запустил скрипт указанным выше способом, в mitmproxy появились запросы:
По ним можно перемещаться стрелками и выбирать для просмотра нажатием кнопки Enter:
Между вкладками Request/Response можно перемещаться кнопкой Tab. Перехваченный Response:
Выход в основное окно — «q», очистка истории запросов, если их много — «C». Отфильтровать запросы по регэкспу — кнопка «l» (первая буква в слове «limit»).
С помощью фильтра i можно перехватывать и задерживать запросы по различным условиям и оперативно исправлять в них данные или вовсе обрывать. Например, я нажал кнопку «i», задал выражение «post», и при отправке запроса к httpbin.com/post соединение было приостановлено до одобрения. Одобрить можно отдельно request и response, предварительно отредактировав нужные данные. На скриншоте я одобрил request, а response сейчас будем редактировать (всё это время скрипт ожидает соединения).
Нажал «e», внизу появился выбор, что редактируем: код и сообщение ответа («HTTP 200 OK»), заголовок или тело ответа. В скриншоте выбрано тело ответа:
В args с помощью внешнего редактора (конечно, vim) заменили "q": "1"
на "q": "100500"
:
И нажали «a». В результате соединение завершилось, клиенту вернулся «неправильный» ответ и тестовая функция завершилось с ошибкой:
$ HTTP_PROXY=http://localhost:3128 HTTPS_PROXY=http://localhost:3128 python u.py F ====================================================================== FAIL: test_cookie_post (__main__.TestHttpBin) ---------------------------------------------------------------------- Traceback (most recent call last): File "u.py", line 19, in test_cookie_post self.assertEqual(response.json()['args']['q'], '1') AssertionError: u'100500' != '1' ---------------------------------------------------------------------- Ran 1 test in 53.721s FAILED (failures=1)
Конечно, сидеть и вручную переписывать данные неправильно (да и вообще неправильно переписывать данные, но мы тестировщики, нам можно), поэтому mitmproxy предоставляет возможность автоматического исправления пропускаемого трафика. Подробно эти и многие другие возможности описаны в документации.
Такой функциональности было бы более чем достаточно для отладки небраузерных HTTP-клиентов, однако аббревиатура «MiTM» (man in the middle) всё же ассоциируется с перехватом SSL-трафика, и тут mitmproxy на высоте! Указав дополнительную переменную окружения
HTTPS_PROXY=http://localhost:3128
, можно перенаправить все запросы к https через запущенный прокси, и они также будут видны. Конечно, при этом клиенту будет отдаваться самоподписанный сертификат, и нормальная ssl-библиотека будет ругаться на неправильную подпись, однако в отладочных целях можно подавить эту ругань (опция ‘verify=None’ у requests), а в Firefox и вовсе импортировать сертификат CA mitmproxy, как написано здесь.
Вкратце коснусь некоторых фич mitmproxy, полезных в основном для тестировщиков, особенно для pen-tester’ов:
- anticache: подавление заголовков if-modified-since и if-none-match в запросе, таким образом гарантируется полный ответ от сервера, даже если браузер сообщает, что документ есть в кэше;
- client-side replay: можно записывать трафик от клиента к серверу и воспроизводить его, например, записать сессию получения каких-нибудь данных и при необходимости получать их, почти полностью имитируя при этом клиента;
- server-side replay: можно воспроизводить для клиента записанные ранее ответы от сервера, если параметры и/или заголовки запроса соответствуют заданным;
- замены: можно заменять один текст на другой в разных местах. В документации предлагается use-case для этой фичи: заменять XSS на длинный код эксплойта из файла;
- добавление дополнительных заголовков, кук или авторизации ко всем проксируемым запросам
- режим reverse proxy, когда все запросы отсылаются к вышестоящему серверу. В таком режиме mitmproxy можно использовать как временную прослойку между nginx и http upstream и в реальном времени наблюдать и перехватывать запросы. Конечно исключительно в режиме отладки или на тестовом сервере, в production такое пускать нельзя из-за периодических падений.
Удачной отладки!
P.S. Если при запуске mitmproxy возникает ошибка импорта Image из PIL, например:
Traceback (most recent call last): File "/home/user/bin/mitmproxy", line 5, in.... File "/home/user/lib/python2.7/site-packages/mitmproxy-0.8.1-py2.7.egg/libmproxy/console/flowview.py", line 18, in import common, grideditor, contentview File "/home/user/lib/python2.7/site-packages/mitmproxy-0.8.1-py2.7.egg/libmproxy/console/contentview.py", line 3, in <module> from PIL import Image ImportError: No module named PIL
это значит, что у вас устаревшая версия mitmproxy и нужно применить патч.
[...] Приложения, Статьи VN:R_U [1.9.22_1171]Rating: 0.0/5 (0 votes cast)Оригинал статьи находится на [...]