[ Content | View menu ]

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 и нужно применить патч.

«
»

1 комментарий

Write a comment - TrackBack - RSS Comments

  1. Pingback from QA Club NN » mitmproxy — консольный firebug:

    [...] Приложения, Статьи VN:R_U [1.9.22_1171]Rating: 0.0/5 (0 votes cast)Оригинал статьи находится на [...]

    25.05.2013 @ 13:16
Write comment

Я не робот.