diff --git a/MITMPROXY.md b/MITMPROXY.md new file mode 100644 index 0000000..1d2351d --- /dev/null +++ b/MITMPROXY.md @@ -0,0 +1,156 @@ +# Mitmproxy → HAR + +## Быстрый старт + +### Вариант 1: mitmweb (проще всего) + +```bash +# 1. Запустить mitmweb +mitmweb --mode regular + +# 2. Открыть в браузере +http://127.0.0.1:8081 + +# 3. Настроить прокси в браузере +# localhost:8081 + +# 4. Выполнить действия на Kwork + +# 5. Экспорт: File → Export → HAR +``` + +### Вариант 2: mitmdump + конвертация + +```bash +# 1. Записать трафик +mitmdump -w kwork-dump.mitm + +# 2. Конвертировать в HAR +python3 scripts/mitmproxy-to-har.py kwork-dump.mitm kwork-dump.har + +# 3. Анализировать +jq '.log.entries | length' kwork-dump.har +``` + +## Настройка прокси + +### Системный прокси (Linux) + +```bash +export http_proxy=http://127.0.0.1:8081 +export https_proxy=http://127.0.0.1:8081 +``` + +### Firefox + +1. Настройки → Прокси +2. Manual proxy configuration +3. HTTP Proxy: 127.0.0.1:8081 +4. ☑ Also use for HTTPS + +### Chrome + +```bash +# Запустить с прокси +google-chrome --proxy-server="127.0.0.1:8081" +``` + +## Установка сертификата + +```bash +# 1. Открыть в браузере +http://mitm.it + +# 2. Скачать сертификат для вашей ОС + +# 3. Установить в доверенные +# Linux: +sudo cp mitmproxy-ca-cert.pem /usr/local/share/ca-certificates/ +sudo update-ca-certificates + +# 4. Перезапустить браузер +``` + +## Фильтрация трафика + +```bash +# Только Kwork +mitmdump -w kwork.mitm --set 'filter=~u kwork\.ru' + +# Только API +mitmdump -w kwork-api.mitm --set 'filter=~u /api/' + +# Исключить статику +mitmdump -w kwork.mitm --set 'filter=!~u \.(css|js|png|jpg|gif|svg)' +``` + +## Скрипт для записи Kwork + +```bash +#!/bin/bash +# record-kwork.sh + +echo "Starting mitmproxy recording for Kwork..." +echo "Configure your browser to use proxy: localhost:8081" +echo "Press Ctrl+C when done" + +mitmdump \ + -w kwork-session.mitm \ + --set 'filter=~u kwork\.ru' \ + --set 'ignore_hosts=~u (cdn|counter|yandex|google)' \ + --set 'keep_host_headers=true' + +echo "Converting to HAR..." +python3 scripts/mitmproxy-to-har.py kwork-session.mitm kwork-session.har + +echo "Done! File: kwork-session.har" +echo "Analyze with: jq '.log.entries | length' kwork-session.har" +``` + +## Анализ записанного HAR + +```bash +# Количество запросов +jq '.log.entries | length' kwork-session.har + +# JSON эндпоинты +jq '[.log.entries[] | select(.response.content.mimeType | test("json"; "i")) | .request.url | split("?")[0]] | unique' kwork-session.har + +# Самые большие ответы +jq '[.log.entries[] | {url: .request.url, size: .response.bodySize}] | sort_by(.size) | reverse | .[0:10]' kwork-session.har + +# Авторизация +jq '[.log.entries[].request.headers[] | select(.name | ascii_downcase | test("authorization|cookie"; "i"))] | unique' kwork-session.har +``` + +## Типичные проблемы + +### SSL ошибки + +```bash +# Игнорировать SSL ошибки +mitmdump --set 'ignore_hosts=.*' + +# Или отключить проверку +mitmdump --set 'ssl_insecure=true' +``` + +### WebSocket + +```bash +# WebSocket не экспортируется в HAR +# Используйте --show-websocket для отладки +mitmdump --show-websocket +``` + +### Сжатый трафик + +```bash +# mitmproxy автоматически распаковывает +# Если нужно сырое: +mitmdump --set 'rawtcp=true' +``` + +--- + +_Updated: 2026-03-22_ diff --git a/scripts/mitmproxy-to-har.py b/scripts/mitmproxy-to-har.py new file mode 100644 index 0000000..300c1d2 --- /dev/null +++ b/scripts/mitmproxy-to-har.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +""" +Convert mitmproxy flow dump to HAR format +Usage: mitmproxy-to-har.py +""" + +import json +import sys +from datetime import datetime +from mitmproxy import io +from mitmproxy.http import HTTPFlow + + +def flow_to_har_entry(flow: HTTPFlow) -> dict: + """Convert single flow to HAR entry.""" + if not flow.request or not flow.response: + return None + + entry = { + "startedDateTime": datetime.fromtimestamp(flow.request.timestamp_start).isoformat() + "Z", + "time": int((flow.response.timestamp_end - flow.request.timestamp_start) * 1000) if flow.response.timestamp_end else 0, + "request": { + "method": flow.request.method, + "url": flow.request.url, + "httpVersion": flow.request.http_version, + "headers": [{"name": k, "value": v} for k, v in flow.request.headers.items()], + "queryString": [{"name": k, "value": v} for k, v in flow.request.query.items()], + "cookies": [{"name": k, "value": v} for k, v in flow.request.cookies.items()], + "headersSize": -1, + "bodySize": len(flow.request.content) if flow.request.content else 0, + }, + "response": { + "status": flow.response.status_code, + "statusText": flow.response.reason, + "httpVersion": flow.response.http_version, + "headers": [{"name": k, "value": v} for k, v in flow.response.headers.items()], + "cookies": [{"name": k, "value": v} for k, v in flow.response.cookies.items()], + "content": { + "size": len(flow.response.content) if flow.response.content else 0, + "mimeType": flow.response.headers.get("Content-Type", "unknown").split(";")[0], + "text": flow.response.get_text() if flow.response.content else "" + }, + "redirectURL": flow.response.headers.get("Location", ""), + "headersSize": -1, + "bodySize": len(flow.response.content) if flow.response.content else 0, + }, + "cache": {}, + "timings": { + "send": 0, + "wait": int((flow.response.timestamp_start - flow.request.timestamp_end) * 1000) if flow.response.timestamp_start and flow.request.timestamp_end else 0, + "receive": int((flow.response.timestamp_end - flow.response.timestamp_start) * 1000) if flow.response.timestamp_end and flow.response.timestamp_start else 0, + } + } + + # Add POST data if present + if flow.request.method == "POST" and flow.request.content: + entry["request"]["postData"] = { + "mimeType": flow.request.headers.get("Content-Type", "application/octet-stream"), + "text": flow.request.get_text() if flow.request.content else "" + } + + return entry + + +def convert_mitm_to_har(input_file: str, output_file: str): + """Convert mitmproxy dump to HAR.""" + har = { + "log": { + "version": "1.2", + "creator": { + "name": "mitmproxy-to-har", + "version": "1.0" + }, + "entries": [] + } + } + + with open(input_file, 'rb') as f: + reader = io.FlowReader(f) + for flow in reader.read(): + if isinstance(flow, HTTPFlow): + entry = flow_to_har_entry(flow) + if entry: + har["log"]["entries"].append(entry) + + with open(output_file, 'w', encoding='utf-8') as f: + json.dump(har, f, indent=2, ensure_ascii=False) + + print(f"Converted {len(har['log']['entries'])} flows to {output_file}") + + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: mitmproxy-to-har.py ") + sys.exit(1) + + convert_mitm_to_har(sys.argv[1], sys.argv[2])