Voltar ao blog

mitmproxy para desenvolvedores: interceptação e análise de tráfego HTTPS com exemplos de código em Python

mitmproxy é uma ferramenta poderosa para interceptar e analisar tráfego HTTPS. Abordamos a instalação, configuração de certificados SSL, escrita de scripts e cenários reais de aplicação.

📅5 de agosto de 2026
```html

Está depurando um aplicativo móvel e não entende quais solicitações ele envia ao servidor? Precisa testar o comportamento da API sob diferentes condições ou interceptar a resposta e modificar os dados em tempo real? O mitmproxy resolve todas essas tarefas — é uma ferramenta gratuita e de código aberto que permite controlar completamente o tráfego HTTP e HTTPS entre o cliente e o servidor.

O que é mitmproxy e por que é necessário para o desenvolvedor

O mitmproxy é um proxy MITM (Man-In-The-Middle) interativo de código aberto, escrito em Python. Ele funciona como um intermediário entre seu aplicativo e o servidor: intercepta todas as solicitações e respostas, permitindo visualizá-las, modificá-las, reproduzi-las e salvá-las.

A principal diferença do mitmproxy em relação a proxies comuns é a capacidade de trabalhar com tráfego HTTPS criptografado. A ferramenta gera dinamicamente certificados SSL para cada domínio, permitindo a descriptografia do tráfego em tempo real, sem interromper o funcionamento do aplicativo.

Aqui estão algumas tarefas típicas que os desenvolvedores resolvem com o mitmproxy:

  • Depuração de API — você vê as solicitações e respostas exatas, incluindo cabeçalhos, corpo e códigos de status.
  • Engenharia reversa — analisa como aplicativos e serviços de terceiros funcionam.
  • Teste — substitui as respostas do servidor para verificar casos limite.
  • Automatização — escreve scripts para modificar o tráfego com base em condições.
  • Gravação e reprodução — salva a sessão e a reproduz sem um servidor real.
  • Análise de segurança — verifica se o aplicativo não está transmitindo dados desnecessários.

É importante entender

O mitmproxy é uma ferramenta para testes e desenvolvimento legais. Use-o apenas para analisar o tráfego de aplicativos que você desenvolve ou tem permissão para testar. Interceptar tráfego de terceiros sem permissão viola a legislação.

A ferramenta é fornecida em três variantes: interface interativa de console mitmproxy, interface web mitmweb e utilitário de linha de comando mitmdump. Todas as três usam um núcleo comum e suportam scripts em Python.

Instalação do mitmproxy no Windows, macOS e Linux

O mitmproxy pode ser instalado de várias maneiras. Recomendamos usar pip — isso garante a versão mais recente e uma atualização simples.

Instalação via pip (método universal)

É necessário Python 3.9 ou superior. Verifique a versão do Python:

python --version
# ou
python3 --version

Instalando o mitmproxy:

pip install mitmproxy

Após a instalação, verifique:

mitmproxy --version
# Deve exibir: mitmproxy 10.x.x

Instalação via gerenciadores de pacotes

macOS (Homebrew):

brew install mitmproxy

Linux (Ubuntu/Debian):

sudo apt install mitmproxy
# ou via snap para a versão mais recente:
sudo snap install mitmproxy

Windows: Baixe o instalador do site oficial mitmproxy.org ou use pip no PowerShell com privilégios de administrador.

Execução e verificação básica

Por padrão, o mitmproxy escuta na porta 8080. Inicie a interface web para começar:

# Iniciando a interface web na porta 8080
mitmweb

# Iniciando em outra porta
mitmweb --listen-port 9090

# Interface de console
mitmproxy

Após iniciar mitmweb, abra o navegador no endereço http://127.0.0.1:8081 — esta é a interface web para visualização do tráfego. O próprio proxy funciona na porta 8080.

Configuração de certificados SSL para interceptação de HTTPS

A interceptação de tráfego HTTPS requer a instalação do certificado raiz do mitmproxy no sistema ou navegador. Sem essa etapa, o navegador mostrará um aviso sobre a conexão insegura, e muitos aplicativos podem se recusar a funcionar.

Como isso funciona tecnicamente

Na primeira execução, o mitmproxy cria automaticamente um certificado CA raiz e o salva no diretório ~/.mitmproxy/. Quando um cliente se conecta a um site HTTPS através do proxy, o mitmproxy gera em tempo real um certificado para esse domínio, assinando-o com sua CA. O cliente confia nesse certificado se a CA estiver adicionada às confiáveis — e a descriptografia ocorre de forma transparente.

Instalação do certificado no sistema

Os certificados estão localizados em ~/.mitmproxy/:

  • mitmproxy-ca-cert.pem — para Linux/macOS
  • mitmproxy-ca-cert.cer — para Windows
  • mitmproxy-ca-cert.p12 — para iOS

macOS:

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

Linux (Ubuntu/Debian):

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

Windows: Clique duas vezes no arquivo mitmproxy-ca-cert.cer → "Instalar certificado" → "Computador local" → "Autoridades de certificação raiz confiáveis".

Instalação no navegador Firefox

O Firefox usa seu próprio armazenamento de certificados. Vá para: Configurações → Privacidade e segurança → Certificados → Ver certificados → Autoridades de certificação → Importar. Selecione o arquivo mitmproxy-ca-cert.pem e marque "Confiar na identificação de sites".

Verificação do funcionamento

Configure o navegador para usar o proxy 127.0.0.1:8080 e abra qualquer site HTTPS. Na interface do mitmweb, você deve ver o tráfego descriptografado. Alternativamente — abra http://mitm.it através do proxy configurado: o mitmproxy mostrará instruções para instalar o certificado para sua plataforma.

Três interfaces: mitmproxy, mitmweb e mitmdump

O pacote mitmproxy inclui três utilitários com diferentes interfaces para diferentes cenários de trabalho. Compreender as diferenças ajudará a escolher a ferramenta certa para cada tarefa.

Utilitário Interface Quando usar Características
mitmproxy TUI de console Depuração interativa no terminal Requer terminal com suporte a cores, poderoso filtro
mitmweb Navegador web Análise visual do tráfego UI amigável, suporte a filtros, exportação
mitmdump CLI (stdout) Scripts, CI/CD, automação Sem interatividade, saída para arquivo ou pipe

Flags úteis de execução

# Gravar tráfego em um arquivo
mitmdump -w traffic.dump

# Reproduzir tráfego gravado
mitmdump -r traffic.dump

# Filtragem: apenas solicitações para um domínio específico
mitmproxy --filter "~d api.example.com"

# Executar no modo proxy transparente
mitmproxy --mode transparent

# Executar como proxy upstream (cadeia de proxy)
mitmproxy --mode upstream:http://upstream-proxy:8080

# Especificando uma porta específica
mitmweb --listen-port 9090 --web-port 9091

# Executar com um script
mitmproxy -s my_script.py

Sintaxe de filtros do mitmproxy

O mitmproxy suporta uma poderosa linguagem de filtros para selecionar as solicitações desejadas:

# ~d — filtro por domínio
~d api.example.com

# ~u — filtro por URL (regex)
~u /api/v2/users

# ~m — filtro por método HTTP
~m POST

# ~s — apenas respostas
~s ~c 404

# ~c — filtro por código de status
~c 500

# Combinação (E)
~d api.example.com & ~m POST

# Combinação (OU)
~c 404 | ~c 500

# NÃO
!~d static.example.com

Escrita de scripts em Python: interceptação e modificação de tráfego

Scripts são o principal superpoder do mitmproxy. Com eles, você pode modificar automaticamente solicitações e respostas, registrar dados no formato desejado, simular erros de servidor e muito mais. Os scripts são escritos em Python e utilizam um modelo baseado em eventos.

Eventos principais (hooks)

Hook Quando é chamado Objeto
request Recebida uma solicitação do cliente flow.request
response Recebida uma resposta do servidor flow.response
error Erro de conexão flow.error
tls_start_client Início do handshake TLS com o cliente tls_start

Exemplo 1: registrando solicitações em um arquivo

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

def request(flow: mitmproxy.http.HTTPFlow) -> None:
    """Registramos cada solicitação em um arquivo 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:
    """Registramos respostas com código de erro."""
    if flow.response.status_code >= 400:
        print(f"[ERROR] {flow.request.method} {flow.request.pretty_url} "
              f"-> {flow.response.status_code}")

Executando o script:

mitmproxy -s logger.py

Exemplo 2: modificação de solicitações — substituição de cabeçalhos

# modify_headers.py
from mitmproxy import http

def request(flow: http.HTTPFlow) -> None:
    """Substituímos o User-Agent e adicionamos um cabeçalho personalizado."""
    if "api.example.com" in flow.request.pretty_host:
        # Substituição do 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"
        )
        # Adicionando cabeçalho de autorização
        flow.request.headers["X-Custom-Token"] = "test-token-12345"
        # Removendo cabeçalho
        if "X-Debug-Info" in flow.request.headers:
            del flow.request.headers["X-Debug-Info"]

Exemplo 3: substituição da resposta do servidor (mock)

# mock_response.py
from mitmproxy import http
import json

def request(flow: http.HTTPFlow) -> None:
    """Interceptamos a solicitação e retornamos uma resposta mock, sem acessar o servidor."""
    if flow.request.pretty_url.endswith("/api/v1/user/profile"):
        # Criamos uma resposta mock
        mock_data = {
            "id": 42,
            "name": "Test User",
            "email": "[email protected]",
            "premium": True  # Testando funcionalidade premium
        }
        flow.response = http.Response.make(
            200,  # Código de status
            json.dumps(mock_data),  # Corpo da resposta
            {"Content-Type": "application/json"}  # Cabeçalhos
        )

def response(flow: http.HTTPFlow) -> None:
    """Modificamos a resposta real do servidor."""
    if "/api/v1/products" in flow.request.pretty_url:
        try:
            data = json.loads(flow.response.text)
            # Adicionamos um campo a cada produto
            for product in data.get("items", []):
                product["debug_info"] = "intercepted"
            flow.response.text = json.dumps(data)
        except (json.JSONDecodeError, KeyError):
            pass

Exemplo 4: simulação de conexão lenta e erros

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

def response(flow: http.HTTPFlow) -> None:
    """Engenharia do caos: atrasos e erros aleatórios para teste."""
    # Adicionamos um atraso aleatório de 0 a 2 segundos
    if "api.example.com" in flow.request.pretty_host:
        delay = random.uniform(0, 2.0)
        time.sleep(delay)

    # 10% de chance de resposta 503
    if random.random() < 0.1:
        flow.response = http.Response.make(
            503,
            json.dumps({"error": "Service Unavailable"}),
            {"Content-Type": "application/json"}
        )

Interceptação de tráfego de aplicativos móveis

A análise de tráfego de aplicativos móveis é uma das tarefas mais comuns ao usar o mitmproxy. Isso é especialmente útil ao realizar engenharia reversa de APIs de aplicativos móveis ou testar seu próprio aplicativo em um dispositivo real.

Configuração no Android

Passo 1. Certifique-se de que o telefone e o computador estão na mesma rede Wi-Fi.

Passo 2. Inicie o mitmproxy no computador:

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

Passo 3. No Android: Configurações → Wi-Fi → mantenha pressionada a rede → Alterar rede → Avançado → Proxy → Manual. Insira o IP do computador e a porta 8080.

Passo 4. Instalação do certificado no Android: abra o navegador no dispositivo, vá para http://mitm.it e baixe o certificado para Android. Em seguida: Configurações → Segurança → Instalar certificado → Certificado CA.

Android 7+ e Pinagem de Certificado

A partir do Android 7.0, aplicativos não confiam por padrão em certificados CA personalizados. Para interceptar o tráfego de tais aplicativos, será necessário acesso root ou modificação do network_security_config.xml no APK. Para aplicativos com SSL Pinning, use Frida ou Xposed Framework para contornar a verificação do certificado.

Configuração no iOS

Passo 1. Configure o proxy da mesma forma que no Android: Configurações → Wi-Fi → toque em (i) ao lado da rede → Configurar proxy → Manual.

Passo 2. Abra o Safari e vá para http://mitm.it — baixe o certificado para iOS.

Passo 3. Instale o perfil: Configurações → Perfil baixado → Instalar.

Passo 4. Ative a confiança no certificado: Configurações → Geral → Sobre → Confiar em certificados — ative o interruptor para mitmproxy.

Interceptação de tráfego de um aplicativo específico via Python

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

# Domínios do aplicativo de interesse
TARGET_DOMAINS = ["api.myapp.com", "cdn.myapp.com"]

def response(flow: http.HTTPFlow) -> None:
    """Analisamos o tráfego do aplicativo móvel."""
    host = flow.request.pretty_host

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

    # Extraímos respostas 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

    # Procuramos tokens nos cabeçalhos da solicitação
    auth_header = flow.request.headers.get("authorization", "")
    if auth_header:
        print(f"[AUTH] Token encontrado: {auth_header[:50]}...")

Cadeia de proxy: mitmproxy + proxy upstream

Um dos cenários poderosos é usar o mitmproxy em conjunto com um servidor proxy externo. Isso permite interceptar e analisar o tráfego (via mitmproxy) e direcioná-lo através de um endereço IP externo (via proxy upstream). Esse esquema é usado ao testar APIs geograficamente dependentes ou ao desenvolver aplicativos que devem funcionar através de um proxy.

Modo proxy upstream

# Direcionando todo o tráfego através de um proxy HTTP upstream
mitmproxy --mode upstream:http://proxy-host:port

# Proxy SOCKS5 upstream
mitmproxy --mode upstream:socks5://proxy-host:port

# Com autenticação
mitmproxy --mode upstream:http://user:password@proxy-host:port

# Através do mitmweb com upstream
mitmweb --mode upstream:http://proxy-host:port

Nesse modo, o mitmproxy aceita solicitações localmente, descriptografa o HTTPS, permite que você as analise e modifique, e então as envia através do proxy externo. Isso é especialmente conveniente ao testar APIs disponíveis apenas de determinadas regiões.

Para essas tarefas, proxies residenciais são uma boa opção — eles têm endereços IP reais de usuários domésticos dos países desejados, permitindo testar corretamente as respostas geograficamente dependentes da API.

Seleção dinâmica de proxy upstream em script

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

# Lista de proxies para rotação
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:
    """Rotação de proxies upstream para cada solicitação."""
    global proxy_index

    # Direcionando solicitações para a API através de diferentes proxies
    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"Usando proxy: {proxy_url} para {flow.request.pretty_url}")

Proxy transparente (modo transparente)

No modo transparente, o aplicativo não sabe que seu tráfego está sendo interceptado — não é necessário configurar o proxy nas configurações. Isso requer configuração do iptables/pf no nível do sistema operacional:

# Executando no modo transparente
mitmproxy --mode transparent --listen-port 8080

# Configurando iptables para redirecionar tráfego (Linux)
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

Cenários práticos de aplicação mitmproxy

Vamos considerar tarefas específicas que os desenvolvedores resolvem com o mitmproxy em projetos reais.

Cenário 1: Testando a API sem alterar o servidor

Imagine: você precisa verificar como o frontend lida com uma resposta com um array de dados vazio ou um erro de autorização 401, mas reproduzir isso em um servidor de teste é difícil. O mitmproxy permite substituir a resposta em tempo real:

# test_edge_cases.py
from mitmproxy import http
import json

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

    # Teste: lista de produtos vazia
    if "/api/products" in url and "test_empty=1" in url:
        flow.response.text = json.dumps({"items": [], "total": 0})

    # Teste: token expirado
    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"}
        )

    # Teste: limite de solicitações excedido
    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"}
        )

Cenário 2: Gravação e reprodução de sessão

Útil para criar fixtures de teste ou demonstrar funcionalidades sem um servidor real:

# Gravar sessão em um arquivo
mitmdump -w session.dump --filter "~d api.example.com"

# Reproduzir sessão gravada (offline)
mitmdump -r session.dump

# Converter para formato HAR para análise
mitmdump -r session.dump --flow-detail 3 > session.txt

Cenário 3: Documentação automática da API

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

# Dicionário para acumular informações sobre os endpoints
endpoints = defaultdict(lambda: {"methods": set(), "status_codes": set(),
                                  "request_fields": set(), "response_fields": set()})

def _extract_fields(data, prefix=""):
    """Extraímos campos de JSON recursivamente."""
    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

    # Normalizamos a URL (removendo 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)

    # Extraímos campos da solicitação
    if flow.request.text:
        try:
            req_data = json.loads(flow.request.text)
            ep["request_fields"].update(_extract_fields(req_data))
        except json.JSONDecodeError:
            pass

    # Extraímos campos da resposta
    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():
    """Exibimos a documentação ao finalizar."""
    print("\n=== DOCUMENTAÇÃO DA API ===\n")
    for endpoint, info in sorted(endpoints.items()):
        print(f"Endpoint: {endpoint}")
        print(f"  Códigos de status: {sorted(info['status_codes'])}")
        if info["request_fields"]:
            print(f"  Campos da solicitação: {sorted(info['request_fields'])}")
        if info["response_fields"]:
            print(f"  Campos da resposta: {sorted(info['response_fields'])}")
        print()

Cenário 4: Testando respostas geograficamente dependentes

Ao desenvolver aplicativos com conteúdo regional, é importante verificar como a API responde a solicitações de diferentes países. Para isso, o mitmproxy é executado no modo upstream com proxies de data center das regiões desejadas — é uma maneira rápida e confiável de simular solicitações de países específicos.

# geo_test.py
from mitmproxy import http

def response(flow: http.HTTPFlow) -> None:
    """Registramos cabeçalhos e dados geograficamente dependentes."""
    # Verificamos qual conteúdo o servidor retorna
    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}")

    # Procuramos menções a moedas e locais na resposta
    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}")

Cenário 5: Usando mitmproxy em CI/CD

O mitmdump é ideal para testes de integração em um pipeline de CI/CD — ele é executado como um processo em segundo plano, grava o tráfego e termina junto com os testes:

#!/bin/bash
# ci_test.sh

# Iniciando mitmdump em segundo plano
mitmdump -w test_traffic.dump -s ci_assertions.py &
MITM_PID=$!

# Dando tempo para o proxy iniciar
sleep 1

# Executando testes com o proxy
export HTTP_PROXY=http://127.0.0.1:8080
export HTTPS_PROXY=http://127.0.0.1:8080
pytest tests/integration/ -v

# Parando o mitmdump
kill $MITM_PID

# Analisando o tráfego gravado
mitmdump -r test_traffic.dump -s analyze_traffic.py

O script ci_assertions.py pode verificar se o aplicativo não está fazendo solicitações desnecessárias, não está transmitindo dados sensíveis em texto não criptografado e está seguindo os contratos da API.

Cenário 6: Análise de tráfego de parser

Ao desenvolver parsers, o mitmproxy ajuda a entender quais solicitações o navegador faz ao carregar uma página — incluindo solicitações XHR/fetch para a API que não são visíveis no código-fonte HTML. Isso permite que você acesse diretamente a API do site em vez de fazer parsing do HTML. Ao desenvolver tais soluções, proxies residenciais são frequentemente usados para rotação de IP, a fim de evitar bloqueios ao coletar dados.

Conclusão

O mitmproxy é uma das ferramentas mais poderosas no arsenal de um desenvolvedor para trabalhar com tráfego HTTP/HTTPS. Ele combina funções de depurador, ambiente de teste, documentador de API e ferramenta de análise de segurança. As três interfaces — console, web e CLI — cobrem todos os cenários: desde depuração interativa até automação em CI/CD.

```