بازگشت به وبلاگ

mitmproxy برای توسعه‌دهندگان: ره‌گیری و تحلیل ترافیک HTTPS با مثال‌های کد در پایتون

mitmproxy یک ابزار قدرتمند برای ضبط و تجزیه و تحلیل ترافیک HTTPS است. نصب، تنظیم گواهی‌های SSL، نوشتن اسکریپت‌ها و سناریوهای واقعی استفاده را بررسی می‌کنیم.

📅۱۴ مرداد ۱۴۰۵
```html

آیا شما در حال اشکال‌زدایی یک برنامه موبایل هستید و نمی‌دانید چه درخواست‌هایی به سرور ارسال می‌شود؟ آیا نیاز دارید رفتار API را تحت شرایط مختلف آزمایش کنید یا پاسخ را ضبط کرده و داده‌ها را در حین اجرا تغییر دهید؟ mitmproxy همه این وظایف را حل می‌کند — این یک ابزار رایگان و متن‌باز است که به شما امکان می‌دهد به طور کامل بر ترافیک HTTP و HTTPS بین کلاینت و سرور کنترل داشته باشید.

mitmproxy چیست و چرا برای توسعه‌دهنده نیاز است

mitmproxy یک پروکسی MITM (Man-In-The-Middle Proxy) تعاملی با کد منبع باز است که به زبان Python نوشته شده است. این ابزار به عنوان واسطه‌ای بین برنامه شما و سرور عمل می‌کند: تمام درخواست‌ها و پاسخ‌ها را ضبط می‌کند و به شما امکان می‌دهد آنها را مشاهده، تغییر، بازتولید و ذخیره کنید.

تفاوت اصلی mitmproxy با پروکسی‌های معمولی این است که می‌تواند با ترافیک HTTPS رمزگذاری شده کار کند. این ابزار به طور دینامیک گواهی‌نامه‌های SSL را برای هر دامنه تولید می‌کند که به شما امکان می‌دهد ترافیک را در حین اجرا رمزگشایی کنید، بدون اینکه عملکرد برنامه مختل شود.

در اینجا وظایف معمولی وجود دارد که توسعه‌دهندگان با استفاده از mitmproxy حل می‌کنند:

  • اشکال‌زدایی API — مشاهده درخواست‌ها و پاسخ‌های دقیق، از جمله هدرها، بدنه و کدهای وضعیت.
  • مهندسی معکوس — تحلیل نحوه کار برنامه‌ها و خدمات شخص ثالث.
  • آزمایش — تغییر پاسخ‌های سرور برای بررسی موارد مرزی.
  • خودکارسازی — نوشتن اسکریپت‌ها برای تغییر ترافیک بر اساس شرایط.
  • ضبط و بازتولید — ذخیره جلسه و بازتولید آن بدون سرور واقعی.
  • تحلیل امنیتی — بررسی اینکه آیا برنامه داده‌های اضافی ارسال می‌کند یا خیر.

مهم است که درک کنید

mitmproxy ابزاری برای آزمایش و توسعه قانونی است. از آن فقط برای تحلیل ترافیک برنامه‌هایی که شما توسعه می‌دهید یا حق آزمایش آنها را دارید، استفاده کنید. ضبط ترافیک دیگران بدون اجازه قوانین را نقض می‌کند.

این ابزار در سه نسخه ارائه می‌شود: رابط تعاملی کنسولی mitmproxy، رابط وب mitmweb و ابزار خط فرمان mitmdump. همه این سه از یک هسته استفاده می‌کنند و از اسکریپت‌های Python پشتیبانی می‌کنند.

نصب mitmproxy بر روی ویندوز، macOS و لینوکس

mitmproxy به چندین روش نصب می‌شود. ما توصیه می‌کنیم از pip استفاده کنید — این روش نسخه به‌روز و به‌روزرسانی آسان را فراهم می‌کند.

نصب از طریق pip (روش عمومی)

به Python 3.9 یا جدیدتر نیاز دارید. نسخه Python را بررسی کنید:

python --version
# یا
python3 --version

نصب mitmproxy:

pip install mitmproxy

پس از نصب، بررسی کنید:

mitmproxy --version
# باید خروجی: mitmproxy 10.x.x را نشان دهد

نصب از طریق مدیران بسته

macOS (Homebrew):

brew install mitmproxy

لینوکس (Ubuntu/Debian):

sudo apt install mitmproxy
# یا از طریق snap برای نسخه به‌روز:
sudo snap install mitmproxy

ویندوز: نصب‌کننده را از وب‌سایت رسمی mitmproxy.org دانلود کنید یا از pip در PowerShell با حقوق مدیر استفاده کنید.

اجرای اولیه و بررسی پایه

به طور پیش‌فرض mitmproxy به پورت 8080 گوش می‌دهد. برای شروع کار، رابط وب را اجرا کنید:

# اجرای رابط وب در پورت 8080
mitmweb

# اجرای در پورت دیگر
mitmweb --listen-port 9090

# رابط کنسولی
mitmproxy

پس از اجرای mitmweb، مرورگر را به آدرس http://127.0.0.1:8081 باز کنید — این رابط وب برای مشاهده ترافیک است. خود پروکسی در پورت 8080 کار می‌کند.

تنظیم گواهی‌نامه‌های SSL برای ضبط HTTPS

ضبط ترافیک HTTPS نیاز به نصب گواهی‌نامه ریشه mitmproxy در سیستم یا مرورگر دارد. بدون این مرحله، مرورگر هشدار عدم امنیت اتصال را نشان می‌دهد و بسیاری از برنامه‌ها به طور کلی از کار می‌افتند.

چگونه این کار به طور فنی انجام می‌شود

هنگام اولین اجرای mitmproxy، به طور خودکار یک گواهی CA ریشه ایجاد می‌شود و در دایرکتوری ~/.mitmproxy/ ذخیره می‌شود. وقتی کلاینت به یک سایت HTTPS از طریق پروکسی متصل می‌شود، mitmproxy به طور دینامیک گواهی‌نامه‌ای برای این دامنه تولید می‌کند و آن را با CA خود امضا می‌کند. کلاینت به این گواهی‌نامه اعتماد می‌کند، اگر CA به لیست مورد اعتماد اضافه شده باشد — و رمزگشایی به صورت شفاف انجام می‌شود.

نصب گواهی‌نامه در سیستم

گواهی‌نامه‌ها در ~/.mitmproxy/ قرار دارند:

  • mitmproxy-ca-cert.pem — برای لینوکس/macOS
  • mitmproxy-ca-cert.cer — برای ویندوز
  • mitmproxy-ca-cert.p12 — برای iOS

macOS:

sudo security add-trusted-cert -d -r trustRoot \
  -k /Library/Keychains/System.keychain \
  ~/.mitmproxy/mitmproxy-ca-cert.pem

لینوکس (Ubuntu/Debian):

sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem \
  /usr/local/share/ca-certificates/mitmproxy.crt
sudo update-ca-certificates

ویندوز: بر روی فایل mitmproxy-ca-cert.cer دوبار کلیک کنید → «نصب گواهی‌نامه» → «کامپیوتر محلی» → «مراکز صدور گواهی‌نامه ریشه معتبر».

نصب در مرورگر Firefox

Firefox از مخزن گواهی‌نامه‌های خود استفاده می‌کند. به مسیر زیر بروید: تنظیمات → حریم خصوصی و امنیت → گواهی‌نامه‌ها → مشاهده گواهی‌نامه‌ها → مراکز صدور گواهی‌نامه → وارد کردن. فایل mitmproxy-ca-cert.pem را انتخاب کرده و گزینه «به عنوان گواهی‌نامه‌های شناسایی وب‌سایت‌ها اعتماد کنید» را علامت بزنید.

بررسی عملکرد

مرورگر را برای استفاده از پروکسی 127.0.0.1:8080 تنظیم کرده و هر وب‌سایت HTTPS را باز کنید. در رابط mitmweb باید ترافیک رمزگشایی شده را مشاهده کنید. به طور جایگزین — http://mitm.it را از طریق پروکسی تنظیم شده باز کنید: mitmproxy دستورالعمل‌های نصب گواهی‌نامه را برای پلتفرم شما نشان می‌دهد.

سه رابط: mitmproxy، mitmweb و mitmdump

بسته mitmproxy شامل سه ابزار با رابط‌های مختلف برای سناریوهای کاری مختلف است. درک تفاوت‌ها به شما کمک می‌کند تا ابزار مناسب را برای هر وظیفه انتخاب کنید.

ابزار رابط کی استفاده شود ویژگی‌ها
mitmproxy TUI کنسولی اشکال‌زدایی تعاملی در ترمینال نیاز به ترمینال با پشتیبانی از رنگ‌ها، فیلتر قدرتمند
mitmweb مرورگر وب تحلیل بصری ترافیک UI راحت، پشتیبانی از فیلترها، صادرات
mitmdump CLI (stdout) اسکریپت‌ها، CI/CD، خودکارسازی بدون تعامل، خروجی به فایل یا pipe

پرچم‌های مفید برای اجرا

# ضبط ترافیک در فایل
mitmdump -w traffic.dump

# بازتولید ترافیک ضبط شده
mitmdump -r traffic.dump

# فیلتر کردن: فقط درخواست‌ها به دامنه خاص
mitmproxy --filter "~d api.example.com"

# اجرای در حالت پروکسی شفاف
mitmproxy --mode transparent

# اجرای به عنوان پروکسی upstream (زنجیره پروکسی)
mitmproxy --mode upstream:http://upstream-proxy:8080

# تعیین پورت خاص
mitmweb --listen-port 9090 --web-port 9091

# اجرای با اسکریپت
mitmproxy -s my_script.py

نحو فیلترهای mitmproxy

mitmproxy از زبان فیلتر قدرتمندی برای انتخاب درخواست‌های مورد نظر پشتیبانی می‌کند:

# ~d — فیلتر بر اساس دامنه
~d api.example.com

# ~u — فیلتر بر اساس URL (regex)
~u /api/v2/users

# ~m — فیلتر بر اساس روش HTTP
~m POST

# ~s — فقط پاسخ‌ها
~s ~c 404

# ~c — فیلتر بر اساس کد وضعیت
~c 500

# ترکیب (AND)
~d api.example.com & ~m POST

# ترکیب (OR)
~c 404 | ~c 500

# NOT
!~d static.example.com

نوشتن اسکریپت‌ها با Python: ضبط و تغییر ترافیک

اسکریپت‌ها قدرت اصلی mitmproxy هستند. با استفاده از آنها می‌توانید به طور خودکار درخواست‌ها و پاسخ‌ها را تغییر دهید، داده‌ها را در فرمت مورد نظر ثبت کنید، خطاهای سرور را شبیه‌سازی کنید و کارهای دیگر. اسکریپت‌ها به زبان Python نوشته می‌شوند و از مدل رویداد استفاده می‌کنند.

رویدادهای اصلی (hook ها)

hook کی فراخوانی می‌شود شیء
request درخواست از کلاینت دریافت شده است flow.request
response پاسخ از سرور دریافت شده است flow.response
error خطای اتصال flow.error
tls_start_client شروع TLS handshake با کلاینت tls_start

مثال 1: ثبت درخواست‌ها در فایل

# logger.py
import mitmproxy.http
import json
from datetime import datetime

def request(flow: mitmproxy.http.HTTPFlow) -> None:
    """هر درخواست را در فایل JSON ثبت می‌کنیم."""
    log_entry = {
        "timestamp": datetime.now().isoformat(),
        "method": flow.request.method,
        "url": flow.request.pretty_url,
        "headers": dict(flow.request.headers),
        "body": flow.request.text if flow.request.text else None
    }
    with open("requests.log", "a") as f:
        f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")

def response(flow: mitmproxy.http.HTTPFlow) -> None:
    """پاسخ‌ها با کد خطا را ثبت می‌کنیم."""
    if flow.response.status_code >= 400:
        print(f"[ERROR] {flow.request.method} {flow.request.pretty_url} "
              f"-> {flow.response.status_code}")

اجرای اسکریپت:

mitmproxy -s logger.py

مثال 2: تغییر درخواست‌ها — تغییر هدرها

# modify_headers.py
from mitmproxy import http

def request(flow: http.HTTPFlow) -> None:
    """User-Agent را تغییر داده و یک هدر سفارشی اضافه می‌کنیم."""
    if "api.example.com" in flow.request.pretty_host:
        # تغییر User-Agent
        flow.request.headers["User-Agent"] = (
            "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) "
            "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1"
        )
        # اضافه کردن هدر مجوز
        flow.request.headers["X-Custom-Token"] = "test-token-12345"
        # حذف هدر
        if "X-Debug-Info" in flow.request.headers:
            del flow.request.headers["X-Debug-Info"]

مثال 3: تغییر پاسخ سرور (mock)

# mock_response.py
from mitmproxy import http
import json

def request(flow: http.HTTPFlow) -> None:
    """درخواست را ضبط کرده و یک پاسخ mock برمی‌گردانیم، بدون اینکه به سرور مراجعه کنیم."""
    if flow.request.pretty_url.endswith("/api/v1/user/profile"):
        # ایجاد پاسخ mock
        mock_data = {
            "id": 42,
            "name": "Test User",
            "email": "[email protected]",
            "premium": True  # تست قابلیت premium
        }
        flow.response = http.Response.make(
            200,  # کد وضعیت
            json.dumps(mock_data),  # بدنه پاسخ
            {"Content-Type": "application/json"}  # هدرها
        )

def response(flow: http.HTTPFlow) -> None:
    """پاسخ واقعی سرور را تغییر می‌دهیم."""
    if "/api/v1/products" in flow.request.pretty_url:
        try:
            data = json.loads(flow.response.text)
            # اضافه کردن فیلد به هر محصول
            for product in data.get("items", []):
                product["debug_info"] = "intercepted"
            flow.response.text = json.dumps(data)
        except (json.JSONDecodeError, KeyError):
            pass

مثال 4: شبیه‌سازی اتصال کند و خطاها

# chaos_testing.py
from mitmproxy import http
import time
import random

def response(flow: http.HTTPFlow) -> None:
    """مهندسی هرج و مرج: تأخیرها و خطاهای تصادفی برای آزمایش."""
    # اضافه کردن تأخیر تصادفی از 0 تا 2 ثانیه
    if "api.example.com" in flow.request.pretty_host:
        delay = random.uniform(0, 2.0)
        time.sleep(delay)

    # 10% احتمال پاسخ 503
    if random.random() < 0.1:
        flow.response = http.Response.make(
            503,
            json.dumps({"error": "Service Unavailable"}),
            {"Content-Type": "application/json"}
        )

ضبط ترافیک برنامه‌های موبایل

تحلیل ترافیک برنامه‌های موبایل یکی از رایج‌ترین وظایف هنگام استفاده از mitmproxy است. این کار به ویژه در مهندسی معکوس API برنامه‌های موبایل یا آزمایش برنامه خود بر روی دستگاه واقعی مفید است.

تنظیمات در Android

مرحله 1. اطمینان حاصل کنید که تلفن و کامپیوتر در یک شبکه Wi-Fi هستند.

مرحله 2. mitmproxy را بر روی کامپیوتر اجرا کنید:

mitmweb --listen-host 0.0.0.0 --listen-port 8080

مرحله 3. در Android: تنظیمات → Wi-Fi → شبکه را نگه دارید → تغییر شبکه → پیشرفته → پروکسی → دستی. IP کامپیوتر و پورت 8080 را وارد کنید.

مرحله 4. نصب گواهی‌نامه در Android: مرورگر را در دستگاه باز کنید، به http://mitm.it بروید و گواهی‌نامه را برای Android دانلود کنید. سپس: تنظیمات → امنیت → نصب گواهی‌نامه → گواهی‌نامه CA.

Android 7+ و Certificate Pinning

از Android 7.0 به بعد، برنامه‌ها به طور پیش‌فرض به گواهی‌نامه‌های CA سفارشی اعتماد نمی‌کنند. برای ضبط ترافیک چنین برنامه‌هایی نیاز به دسترسی ریشه یا تغییر network_security_config.xml در APK دارید. برای برنامه‌هایی با SSL Pinning از Frida یا Xposed Framework برای دور زدن بررسی گواهی‌نامه استفاده کنید.

تنظیمات در iOS

مرحله 1. پروکسی را مشابه Android تنظیم کنید: تنظیمات → Wi-Fi → بر روی (i) کنار شبکه کلیک کنید → تنظیم پروکسی → دستی.

مرحله 2. Safari را باز کرده و به http://mitm.it بروید — گواهی‌نامه را برای iOS دانلود کنید.

مرحله 3. پروفایل را نصب کنید: تنظیمات → پروفایل بارگذاری شده → نصب.

مرحله 4. اعتماد به گواهی‌نامه را فعال کنید: تنظیمات → عمومی → درباره دستگاه → اعتماد به گواهی‌نامه‌ها — سوئیچ را برای mitmproxy فعال کنید.

ضبط ترافیک یک برنامه خاص از طریق Python

# mobile_app_analyzer.py
from mitmproxy import http
import json
import re

# دامنه‌های برنامه مورد نظر
TARGET_DOMAINS = ["api.myapp.com", "cdn.myapp.com"]

def response(flow: http.HTTPFlow) -> None:
    """ترافیک برنامه موبایل را تحلیل می‌کنیم."""
    host = flow.request.pretty_host

    if not any(domain in host for domain in TARGET_DOMAINS):
        return

    # استخراج پاسخ‌های JSON
    content_type = flow.response.headers.get("content-type", "")
    if "application/json" in content_type:
        try:
            data = json.loads(flow.response.text)
            print(f"\n{'='*60}")
            print(f"URL: {flow.request.pretty_url}")
            print(f"Status: {flow.response.status_code}")
            print(f"Response: {json.dumps(data, indent=2, ensure_ascii=False)}")
        except json.JSONDecodeError:
            pass

    # جستجوی توکن‌ها در هدرهای درخواست
    auth_header = flow.request.headers.get("authorization", "")
    if auth_header:
        print(f"[AUTH] Token found: {auth_header[:50]}...")

زنجیره پروکسی: mitmproxy + پروکسی upstream

یکی از سناریوهای قدرتمند — استفاده از mitmproxy در کنار یک سرور پروکسی خارجی است. این امکان را فراهم می‌کند که به طور همزمان ترافیک را ضبط و تحلیل کنید (از طریق mitmproxy) و آن را از طریق یک آدرس IP خارجی هدایت کنید (از طریق پروکسی upstream). این طرح در آزمایش API‌های وابسته به منطقه یا در توسعه برنامه‌هایی که باید از طریق پروکسی کار کنند، استفاده می‌شود.

حالت پروکسی upstream

# هدایت تمام ترافیک از طریق پروکسی HTTP upstream
mitmproxy --mode upstream:http://proxy-host:port

# پروکسی SOCKS5 upstream
mitmproxy --mode upstream:socks5://proxy-host:port

# با احراز هویت
mitmproxy --mode upstream:http://user:password@proxy-host:port

# از طریق mitmweb با upstream
mitmweb --mode upstream:http://proxy-host:port

در این حالت، mitmproxy درخواست‌ها را به صورت محلی دریافت کرده، HTTPS را رمزگشایی می‌کند، به شما امکان می‌دهد آنها را تحلیل و تغییر دهید و سپس از طریق پروکسی خارجی ارسال می‌کند. این به ویژه در آزمایش API‌هایی که فقط از مناطق خاصی قابل دسترسی هستند، راحت است.

برای چنین وظایفی، پروکسی‌های مسکونی بسیار مناسب هستند — آنها دارای آدرس‌های IP واقعی کاربران خانگی از کشورهای مورد نیاز هستند که امکان آزمایش صحیح پاسخ‌های API وابسته به منطقه را فراهم می‌کند.

انتخاب دینامیک پروکسی upstream در اسکریپت

# dynamic_upstream.py
from mitmproxy import http
from mitmproxy.net.server_spec import ServerSpec

# لیست پروکسی برای چرخش
PROXY_LIST = [
    "http://proxy1.example.com:8080",
    "http://proxy2.example.com:8080",
    "http://proxy3.example.com:8080",
]

proxy_index = 0

def request(flow: http.HTTPFlow) -> None:
    """چرخش پروکسی upstream برای هر درخواست."""
    global proxy_index

    # هدایت درخواست‌ها به API از طریق پروکسی‌های مختلف
    if "api.target.com" in flow.request.pretty_host:
        proxy_url = PROXY_LIST[proxy_index % len(PROXY_LIST)]
        proxy_index += 1
        flow.live.change_upstream_proxy_server(
            ServerSpec.from_url(proxy_url)
        )
        print(f"Using proxy: {proxy_url} for {flow.request.pretty_url}")

پروکسی شفاف (transparent mode)

در حالت شفاف، برنامه نمی‌داند که ترافیک آن ضبط می‌شود — نیازی به تنظیم پروکسی در تنظیمات نیست. این نیاز به تنظیم iptables/pf در سطح سیستم‌عامل دارد:

# اجرای در حالت transparent
mitmproxy --mode transparent --listen-port 8080

# تنظیم iptables برای هدایت ترافیک (لینوکس)
sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-port 8080

سناریوهای عملی کاربرد mitmproxy

بیایید به وظایف خاصی که توسعه‌دهندگان با استفاده از mitmproxy در پروژه‌های واقعی حل می‌کنند، نگاهی بیندازیم.

سناریو 1: آزمایش API بدون تغییر سرور

تصور کنید: شما باید بررسی کنید که چگونه فرانت‌اند پاسخ را با آرایه داده‌های خالی یا خطای احراز هویت 401 پردازش می‌کند، اما بازتولید این موضوع در سرور تست دشوار است. mitmproxy به شما این امکان را می‌دهد که پاسخ را به طور مستقیم در حین اجرا تغییر دهید:

# test_edge_cases.py
from mitmproxy import http
import json

def response(flow: http.HTTPFlow) -> None:
    url = flow.request.pretty_url

    # تست: لیست خالی محصولات
    if "/api/products" in url and "test_empty=1" in url:
        flow.response.text = json.dumps({"items": [], "total": 0})

    # تست: توکن منقضی شده
    if "/api/user" in url and "test_auth=1" in url:
        flow.response = http.Response.make(
            401,
            json.dumps({"error": "Token expired", "code": "AUTH_001"}),
            {"Content-Type": "application/json"}
        )

    # تست: تجاوز از محدودیت درخواست‌ها
    if "/api/" in url and "test_rate=1" in url:
        flow.response = http.Response.make(
            429,
            json.dumps({"error": "Too Many Requests", "retry_after": 60}),
            {"Content-Type": "application/json",
             "Retry-After": "60"}
        )

سناریو 2: ضبط و بازتولید جلسه

این برای ایجاد فیکست‌های تست یا نمایش عملکرد بدون سرور واقعی مفید است:

# ضبط جلسه در فایل
mitmdump -w session.dump --filter "~d api.example.com"

# بازتولید جلسه ضبط شده (آفلاین)
mitmdump -r session.dump

# تبدیل به فرمت HAR برای تحلیل
mitmdump -r session.dump --flow-detail 3 > session.txt

سناریو 3: مستندسازی خودکار API

# api_documenter.py
from mitmproxy import http
import json
from collections import defaultdict

# دیکشنری برای جمع‌آوری اطلاعات در مورد endpoint ها
endpoints = defaultdict(lambda: {"methods": set(), "status_codes": set(),
                                  "request_fields": set(), "response_fields": set()})

def _extract_fields(data, prefix=""):
    """به طور بازگشتی فیلدها را از JSON استخراج می‌کنیم."""
    fields = set()
    if isinstance(data, dict):
        for key, value in data.items():
            full_key = f"{prefix}.{key}" if prefix else key
            fields.add(full_key)
            fields.update(_extract_fields(value, full_key))
    elif isinstance(data, list) and data:
        fields.update(_extract_fields(data[0], prefix))
    return fields

def response(flow: http.HTTPFlow) -> None:
    if "api.example.com" not in flow.request.pretty_host:
        return

    # نرمال‌سازی URL (حذف ID)
    import re
    path = re.sub(r'/\d+', '/{id}', flow.request.path)
    endpoint = f"{flow.request.method} {path}"

    ep = endpoints[endpoint]
    ep["methods"].add(flow.request.method)
    ep["status_codes"].add(flow.response.status_code)

    # استخراج فیلدهای درخواست
    if flow.request.text:
        try:
            req_data = json.loads(flow.request.text)
            ep["request_fields"].update(_extract_fields(req_data))
        except json.JSONDecodeError:
            pass

    # استخراج فیلدهای پاسخ
    if flow.response.text:
        try:
            resp_data = json.loads(flow.response.text)
            ep["response_fields"].update(_extract_fields(resp_data))
        except json.JSONDecodeError:
            pass

def done():
    """مستندات را در پایان خروجی می‌زنیم."""
    print("\n=== مستندات API ===\n")
    for endpoint, info in sorted(endpoints.items()):
        print(f"Endpoint: {endpoint}")
        print(f"  کدهای وضعیت: {sorted(info['status_codes'])}")
        if info["request_fields"]:
            print(f"  فیلدهای درخواست: {sorted(info['request_fields'])}")
        if info["response_fields"]:
            print(f"  فیلدهای پاسخ: {sorted(info['response_fields'])}")
        print()

سناریو 4: آزمایش پاسخ‌های وابسته به منطقه

هنگام توسعه برنامه‌هایی با محتوای منطقه‌ای، مهم است که بررسی کنید API چگونه به درخواست‌ها از کشورهای مختلف پاسخ می‌دهد. برای این کار mitmproxy در حالت upstream با پروکسی‌های مرکز داده از مناطق مورد نیاز اجرا می‌شود — این یک روش سریع و مطمئن برای شبیه‌سازی درخواست‌ها از کشورهای خاص است.

# geo_test.py
from mitmproxy import http

def response(flow: http.HTTPFlow) -> None:
    """هدرها و داده‌های وابسته به منطقه را ثبت می‌کنیم."""
    # بررسی می‌کنیم که سرور چه محتوایی برمی‌گرداند
    geo_headers = ["cf-ipcountry", "x-country", "x-geo-country"]
    for header in geo_headers:
        value = flow.response.headers.get(header)
        if value:
            print(f"[GEO] {header}: {value} | URL: {flow.request.pretty_url}")

    # جستجوی ارزها و محلی‌سازی‌ها در پاسخ
    if flow.response.text:
        import re
        currencies = re.findall(r'"currency":\s*"([A-Z]{3})"', flow.response.text)
        locales = re.findall(r'"locale":\s*"([a-z]{2}-[A-Z]{2})"', flow.response.text)
        if currencies:
            print(f"[CURRENCY] {currencies}")
        if locales:
            print(f"[LOCALE] {locales}")

سناریو 5: استفاده از mitmproxy در CI/CD

mitmdump به طور ایده‌آل برای آزمایش‌های یکپارچه در خط لوله CI/CD مناسب است — این ابزار به عنوان یک فرایند پس‌زمینه اجرا می‌شود، ترافیک را ضبط می‌کند و همراه با آزمایش‌ها خاتمه می‌یابد:

#!/bin/bash
# ci_test.sh

# اجرای mitmdump در پس‌زمینه
mitmdump -w test_traffic.dump -s ci_assertions.py &
MITM_PID=$!

# به پروکسی زمان می‌دهیم تا راه‌اندازی شود
sleep 1

# اجرای آزمایش‌ها با پروکسی
export HTTP_PROXY=http://127.0.0.1:8080
export HTTPS_PROXY=http://127.0.0.1:8080
pytest tests/integration/ -v

# متوقف کردن mitmdump
kill $MITM_PID

# تحلیل ترافیک ضبط شده
mitmdump -r test_traffic.dump -s analyze_traffic.py

اسکریپت ci_assertions.py می‌تواند بررسی کند که آیا برنامه درخواست‌های اضافی نمی‌کند، داده‌های حساس را در حالت غیر رمزگذاری ارسال نمی‌کند و به قراردادهای API پایبند است.

سناریو 6: تحلیل ترافیک پارسر

هنگام توسعه پارسرها، mitmproxy به درک اینکه چه درخواست‌هایی در هنگام بارگذاری صفحه توسط مرورگر انجام می‌شود، کمک می‌کند — از جمله درخواست‌های XHR/fetch به API که در کد HTML قابل مشاهده نیستند. این امکان را می‌دهد که به طور مستقیم به API سایت دسترسی پیدا کنید به جای تجزیه HTML. هنگام توسعه چنین راه‌حل‌هایی، معمولاً از پروکسی‌های مسکونی برای چرخش IP استفاده می‌شود تا از مسدود شدن هنگام جمع‌آوری داده‌ها جلوگیری شود.

نتیجه‌گیری

mitmproxy یکی از قدرتمندترین ابزارها در زرادخانه توسعه‌دهنده برای کار با ترافیک HTTP/HTTPS است. این ابزار شامل ویژگی‌های اشکال‌زدا، محیط آزمایش، مستندکننده API و ابزار تحلیل امنیتی است. سه رابط — کنسولی، وب و CLI — تمام سناریوها را پوشش می‌دهند: از اشکال‌زدایی تعاملی تا خودکارسازی در CI/CD.

```