Saudações.
Nesse tutorial vou ensinar como instalar e usar o MITMPROXY para analise de requisições HTTP, principalmente para auxilio no desenvolvimento de sistemas, testes de WebHooks, analise de aplicativos.
Pré-requisitos (consta em outros artigos aqui do blog):
- Instalação do Linux (Debian, Alpine) e programas básicos;
- Instalar o Docker ou Podman;
- Proxy-Reverso Traefik para HTTPs com LetsEncrypt;
- Instale os programas Docker e Traefik do artigo:
1 – Apresentando o MITMPROXY
O MITMPROXY é um sistema desenvolvido em Python3 que auxilia no desenvolvimento de aplicações que fazem uso do protocolo HTTP.
Criado para ser uma ferramenta hacker, ele permite interceptar, redirecionar e repetir requisições HTTP.
Seus principais recursos:
- Administração web – Possui dashboard e painel de controle acessível pelo navegador para controlar e assistir o tráfego HTTP;
- Proxy-Reverso – Atua como servidor HTTP e encaminha as requisições recebidas para um servidor interno;
- Proxy-Transparente – Quando colocado como gateway do acesso à Internet, ele pode interceptar o tráfego e buscar os sites solicitados pelos clientes;
- Captura inteligente – Permite criar filtros específicos para protocolos e detalhes da requisição;
Para desenvolvimento de sistemas web, automações e integração com inteligência artificial, usaremos o MITMPROXY para investigar o funcionamento de nossos sistemas.
2 – Preparativos no Docker
Como vou rodar sem usar Portainer, Stack ou DockerCompose, vou criar a rede docker manualmente, assim como os containers dos próximos capítulos.
Docker Network: network_public, 10.249.x.x/16, sem ipv6
# Criar rede de containers
docker network create -d bridge \
-o "com.docker.network.bridge.name"="br-net-public" \
--subnet 10.249.0.0/16 \
--gateway 10.249.255.254 \
network_public;
3 – MITMPROXY como WebHook/ProxyReverso
Nesse exemplo, nosso MITMPROXY vai atuar como proxy-reverso para uma WebHook oficial do N8N.
Nessa topologia, poderemos fornecer a URL dele a sistemas externos, ele irá receber, registrar todos os detalhes da requisição e encaminhar ao N8N (container n8n porta 5678).
O acesso a administração está protegido por senha, altere a senha por segurança.
# Variaveis
NAME="mitmproxy-webhook";
DOMAIN=$(hostname -f);
IMAGE="mitmproxy/mitmproxy:latest";
FQDN_ADMIN="mitmproxy.$DOMAIN";
FQDN_MITM="webhooks.$DOMAIN";
# Senha de acesso administrativo
PASSWORD="tulipa";
# Diretorio de dados persistentes:
DATADIR=/storage/$NAME;
mkdir -p $DATADIR;
# Renovar/rodar:
docker pull $IMAGE;
docker rm -f $NAME 2>/dev/null;
docker run \
-d --restart=always --name $NAME -h $NAME.intranet.br \
--network network_public --ip=10.249.255.241 \
\
-v $DATADIR:/home/mitmproxy \
-p 29080:8080 \
-p 29081:8081 \
\
--label "traefik.enable=true" \
\
--label "traefik.http.routers.${NAME}-web.rule=Host(\`$FQDN_ADMIN\`)" \
--label "traefik.http.routers.${NAME}-web.entrypoints=web,websecure" \
--label "traefik.http.routers.${NAME}-web.tls=true" \
--label "traefik.http.routers.${NAME}-web.tls.certresolver=letsencrypt" \
--label "traefik.http.routers.${NAME}-web.service=${NAME}-web" \
--label "traefik.http.services.${NAME}-web.loadbalancer.server.port=8081" \
--label "traefik.http.services.${NAME}-web.loadbalancer.passHostHeader=true" \
\
--label "traefik.http.routers.${NAME}-mitm.rule=Host(\`$FQDN_MITM\`)" \
--label "traefik.http.routers.${NAME}-mitm.entrypoints=web,websecure" \
--label "traefik.http.routers.${NAME}-mitm.tls=true" \
--label "traefik.http.routers.${NAME}-mitm.tls.certresolver=letsencrypt" \
--label "traefik.http.routers.${NAME}-mitm.service=${NAME}-mitm" \
--label "traefik.http.services.${NAME}-mitm.loadbalancer.server.port=8080" \
--label "traefik.http.services.${NAME}-mitm.loadbalancer.passHostHeader=true" \
\
$IMAGE \
mitmweb \
--web-host 0.0.0.0 \
--web-port 8081 \
--set web_password=$PASSWORD \
--mode reverse:http://n8n:5678;
# Acesso:
echo;
echo "Acesso MITMPROXY:";
echo " WebAdmin.....: $FQDN_MITM senha: $PASSWORD";
echo " Webhook......: $FQDN_ADMIN";
echo;
Agora acesse a administração (WebAdmin) na porta HTTP 8081 ou pelo nome registrado no Traefik ($FQDN_ADMIN acima).
4 – Assistindo os acessos
Na guia “Flow” você poderá assistir em tempo real as requisições!

Testando uma WebHook do N8N:
# Acionando WebHook:
# - Coloque a URL da sua Webhook aqui e substitua o nome FQDN (DNS)
# pela URL do MITMPROXY
WEBHOOK_URL="https://webhooks.SEU-DOMINIO.com/webhook/ws01";
# - Acione a URL:
curl -qs "$WEBHOOK_URL";
5 – Proxy para uso geral em clientes
Uma das maneiras de usar o MITM é como proxy de clientes: os clientes (navegadores, softwares que fazem uso de acesso HTTP e HTTPS em geral) podem ser configurados explicitamente para solicitar URLs por meio do proxy.
O MITM faz mascaramento de certificados para ter acesso completo ao conteúdo trafegado em HTTPs, ou seja:
- Quando você acessar o site, google.com por exemplo, ele irá gerar um certificado para esse domínio em tempo real usando uma unidade certificadora local (CA);
- Os navegadores e clientes HTTPs não gostam muito disso por motivos óbvios de segurança, então será necessário que todos os softwares clientes reconheçam a CA do MITM como válida;
- Como fazemos uso de Docker, vamos compor a CA.
Vamos usar uma única CA própria para duas finalidades:
- Assinar os certificados que o MITM gera em tempo real para os sites acessados;
- Assinar o certificado do próprio servidor proxy (quando o cliente conecta no proxy via HTTPs) em porta dedicada (essa não passa pelo Traefik);
Assim os clientes só precisam confiar em um único arquivo: o certificado da CA.
5.1 – Criando a unidade certificadora CA
O primeiro passo é criar a CA:
- Chave privada para assinatura digital (fica somente no servidor, nunca é distribuída);
- Certificado auto-assinado da CA (esse sim é distribuído aos clientes);
- Gerar formatos de arquivos para diferentes plataformas (PEM, CRT, DER);
- Algumas regras importantes:
- A CA precisa das extensões
CA:TRUEekeyCertSign. Não dependa doopenssl.cnfpadrão da sua distribuição, cada uma tem um padrão diferente. Por isso criamos um arquivo de configuração exclusivo da CA; - O
pathlen:0impede que essa CA crie outras CAs abaixo dela, ela só assina certificados finais; - Use um nome (CN) único, com o ano por exemplo. Isso facilita localizar e remover a CA dos clientes quando ela for trocada;
# Dados da CA
CA_C="BR"; # Codigo ISO do pais
CA_ST="Minas Gerais"; # Estado
CA_L="Belo Horizonte"; # Cidade
CA_O="MITM Company"; # Nome da empresa
CA_OU="TI"; # Nome do departamento
CA_CN="MITM Root CA"; # Nome comum de exibicao e finalidade
CA_DAYS=3650; # Validade da CA (10 anos)
# Criar CA
CADIR="/storage/mitm-proxy/ca";
# Criar diretorio
mkdir -p $CADIR;
# Entrar no diretorio:
cd $CADIR;
# Arquivo de config OpenSSL exclusivo da CA
[ -f mitm-ca.cnf ] || (
echo '[req]';
echo 'distinguished_name = dn';
echo 'prompt = no';
echo 'x509_extensions = v3_ca';
echo '';
echo '[dn]';
echo "C = $CA_C";
echo "ST = $CA_ST";
echo "L = $CA_L";
echo "O = $CA_O";
echo "OU = $CA_OU";
echo "CN = $CA_CN";
echo '';
echo '[v3_ca]';
echo 'basicConstraints = critical, CA:TRUE, pathlen:0';
echo 'keyUsage = critical, keyCertSign, cRLSign';
echo 'subjectKeyIdentifier = hash';
echo 'authorityKeyIdentifier = keyid:always';
) > mitm-ca.cnf;
# Gerar chave privada da CA (4096 bits), legivel somente pelo dono
[ -f mitm-ca-key.pem ] || \
( umask 077; openssl genrsa -out mitm-ca-key.pem 4096 );
# Gerar certificado raiz da CA (PEM puro)
[ -f mitm-ca-cert.pem ] || \
openssl req -x509 -new -sha256 -days $CA_DAYS \
-config mitm-ca.cnf \
-key mitm-ca-key.pem \
-out mitm-ca-cert.pem;
# Copia .crt (extensao exigida pelo update-ca-certificates no Linux)
[ -f mitm-ca-cert.crt ] || \
cp mitm-ca-cert.pem mitm-ca-cert.crt;
# Formato DER (.cer) para Windows/Android
[ -f mitm-ca-cert.cer ] || \
openssl x509 \
-in mitm-ca-cert.pem \
-out mitm-ca-cert.cer \
-outform DER;
# Informativo do certificado (texto separado, nao distribuir como certificado)
[ -f mitm-ca-cert.txt ] || \
openssl x509 -in mitm-ca-cert.pem -noout -text > mitm-ca-cert.txt;
# PKCS-12 da CA (somente certificado, SEM chave privada)
[ -f mitm-ca-cert.p12 ] || \
openssl pkcs12 \
-export \
-nokeys \
-in mitm-ca-cert.pem \
-name "MITM Root CA" \
-out mitm-ca-cert.p12 \
-passout pass:mitm;
# Arquivos procurados pelo MITMPROXY no confdir:
# - mitmproxy-ca.pem: chave privada + certificado da CA
[ -f mitmproxy-ca.pem ] || \
(
umask 077;
cat mitm-ca-key.pem mitm-ca-cert.pem > mitmproxy-ca.pem;
);
# - mitmproxy-ca-cert.pem: somente o certificado da CA
[ -f mitmproxy-ca-cert.pem ] || \
cp mitm-ca-cert.pem mitmproxy-ca-cert.pem;
# Instalando CA no sistema local
# Para utilizar os softwares clientes HTTP no próprio sistema local,
# instale a CA nos certificados raiz.
mkdir -p /etc/ssl/certs;
cp mitm-ca-cert.pem /etc/ssl/certs/mitm-ca-cert.pem;
# Atualizar a base de certificados
update-ca-certificates;
Criar arquivo com chave Diffie-Helman:
# Criar arquivo de chave DH no diretorio da CA
CADIR="/storage/mitm-proxy/ca";
# Entrar no diretorio:
cd $CADIR;
# Gerar arquivo Diffie-Helman (nao faz parte da CA, mas necessario)
[ -f mitmproxy-dhparam.pem ] || \
openssl dhparam -out mitmproxy-dhparam.pem 2048;
5.2 – Criando certificado do servidor proxy
Essa etapa é opcional, mas desejável.
Eu particularmente uso esse certificado como padrão da primeira execução e em seguida troco pelo certificado do LetsEncrypt gerado pelo Traefik (gambiarra minha).
# Dados do certificado servidor
SRV_C="BR"; # Codigo ISO do pais
SRV_O="MITM Company"; # Nome da empresa
SRV_CN="proxy.$(hostname -f)"; # Nome de DNS do servidor proxy (vide FQDN_PROXY)
SRV_DAYS=397; # Validade maxima aceita por Apple/Chrome
# Nomes e IPs pelos quais os clientes acessam o proxy (SAN)
# - altere para os IPs do seu servidor
SRV_SAN="DNS:$SRV_CN, DNS:proxy.intranet.br, IP:45.255.128.2, IP:2001:db8:10::2";
# Gerar certificado do servidor proxy MITM
SRVDIR="/storage/mitm-proxy/srv";
mkdir -p $SRVDIR;
cd $SRVDIR;
# Extensoes de certificado de servidor
(
echo 'basicConstraints = critical, CA:FALSE';
echo 'keyUsage = critical, digitalSignature, keyEncipherment';
echo 'extendedKeyUsage = serverAuth';
echo 'subjectKeyIdentifier = hash';
echo 'authorityKeyIdentifier = keyid,issuer';
echo "subjectAltName = $SRV_SAN";
) > server.ext;
# Gerar chave privada do servidor (RSA 2048)
[ -f server-key.pem ] || \
(
umask 077;
openssl genrsa -out server-key.pem 2048;
);
# Gerar CSR (Certificate Signing Request) - requisicao de certificado para a CA
[ -f server.csr ] || \
openssl req \
-new \
-key server-key.pem \
-out server.csr \
-subj "/C=$SRV_C/O=$SRV_O/CN=$SRV_CN";
# Assinar o certificado do servidor com a CA
[ -f server-cert.pem ] || \
openssl x509 \
-req \
-in server.csr \
-CA ../ca/mitm-ca-cert.pem \
-CAkey ../ca/mitm-ca-key.pem \
-CAcreateserial \
-out server-cert.pem \
-days $SRV_DAYS \
-sha256 \
-extfile server.ext;
# Informativo do certificado (texto separado)
[ -f server-cert.txt ] || \
openssl x509 \
-in server-cert.pem \
-noout -text > server-cert.txt;
# Criar fullchain do certificado (servidor + CA)
[ -f server-fullchain.pem ] || \
cat \
server-cert.pem \
../ca/mitm-ca-cert.pem > server-fullchain.pem;
# Criar bundle completo (chave + cert + cert ca), formato usado pelo MITMPROXY
[ -f server-bundle.pem ] || \
(
umask 077;
cat \
server-key.pem \
server-cert.pem \
../ca/mitm-ca-cert.pem > server-bundle.pem;
);
Conferir certificado do servidor:
# Conferir certificado do servidor
cd /storage/mitm-proxy/srv;
# Assinado pela CA e valido como servidor TLS:
openssl verify \
-CAfile ../ca/mitm-ca-cert.pem \
-purpose sslserver \
-verify_hostname proxy.$(hostname -f) \
server-cert.pem;
# Esperado: server-cert.pem: OK
# Extensoes:
openssl x509 -in server-cert.pem -noout \
-ext basicConstraints,extendedKeyUsage,subjectAltName;
5.3 – Usar certificado do Traefik
Fiz um projeto chamado “traefik-certs” que extrai os certificados do Traefik para um diretório específico, permitindo que outros softwares possam fazer uso deles em forma de arquivo (o Traefik só cria um arquivo acme.json).
Projeto: https://github.com/patrickbrandao/traefik-certs
Com os certificados extraídos em:
- /storage/traefik-certs/certs/domains,
- Diretório do FQDN em:
- /storage/traefik-certs/certs/domains/proxy.dominio.com.br
Requisitos:
- Subir o container do MITM Proxy contendo os labels e declarando o nome de DNS (FQDN) que você pretende usar;
- Aguardar o diretório do FQDN ser criado com os arquivos;
- Reiniciar o MITM Proxy utilizando o certificado gerado pelo Traefik/LetsEntrypt.
5.4 – Cadastrar CA nos sistemas operacionais dos clientes
O cadastro da CA auto-assinada nos clientes é necessária para que os certificados gerados pelo MITM-Proxy em tempo real sejam reconhecidos sem protestos.
No Linux
Baixe o arquivo com o certificado auto-assinado da CA: mitm-ca-cert.pem
# Instale a CA nos certificados raiz.
mkdir -p /etc/ssl/certs;
# Colocar certificado da CA em /etc/ssl/certs
cp mitm-ca-cert.pem /etc/ssl/certs/mitm-ca-cert.pem;
# Atualizar a base de certificados
update-ca-certificates;
No MacOS
Baixe o arquivo com o certificado auto-assinado da CA: mitm-ca-cert.pem
# Instalando no MacOS (executar no MACOS)
# - Baixe os arquivos da CA para o MacOS
# - Execute na pasta da CA:
# -- logar no terminal como root:
sudo su; # ou su -
# ... digite sua senha
# -- registrar ROOT CA propria:
security add-trusted-cert \
-d -p ssl \
-p basic \
-k /Library/Keychains/System.keychain \
mitm-ca-cert.pem; # < certificado auto-ssinado da CA
# -- conferindo (use o nome do campo CA_O ou CA_CN)
security find-certificate -a -c "MITM" -p | openssl x509 -text -noout;
No Firefox
Baixe o arquivo com o certificado auto-assinado da CA no formato PKCS12: mitm-ca-cert.p12
Abra o Firefox:
- Vá no menu de Configurações, Ajustes ou Preferências;
- Localize Certificados;
- Clique no botão Ver certificados;
- Clique no botão “Importar…“;
- Localize o arquivo baixado mitm-ca-cert.p12;
- Confira se a CA aparece na lista de certificados e conclua.
Outros sistemas
O principio é o mesmo dos dois exemplos acima. Importar o certificado auto-assinado da CA, seja o arquivo no formato PEM (mitm-ca-cert.pem) ou PKCS12 (mitm-ca-cert.p12);
5.5 – Rodando o container MITM-PROXY como proxy-server
Requisitos cumpridos acima:
- CA e certificados em /storage/mitm-proxy
- Rede docker
Acesso de administração:
- Via traefik, nome definido na variável FQDN_ADMIN do script abaixo;
- Via IP do servidor na porta HTTPs 8081;
- Senha definido na variável ADMIN_PASSWORD (sem usuário, só a senha)
Acesso para uso do Proxy:
- Via IP do servidor na porta HTTP ou HTTPs 1080 (mapeada na 8080 do mitm)
- Login e senha definido na variável PROXY_LOGIN
Nota: o primeiro acesso aos sites será mais lento que o normal pois o MITMPROXY irá gerar certificados em tempo real para eles e todas as URLs inclusas no site, incluindo de propagandas/ADS e addons.
Criando container:
# Variaveis
NAME="mitm-proxy";
DOMAIN=$(hostname -f); # < dominio do servidor (ex: xpto.com)
IMAGE="mitmproxy/mitmproxy:latest";
FQDN_ADMIN="pxadm.$DOMAIN"; # < nome de DNS da administracao (pxadm.xpto.com)
FQDN_PROXY="proxy.$DOMAIN"; # < nome de DNS do servidor proxy (proxy.xpto.com)
# Senhas para controle de acesso:
ADMIN_PASSWORD="admproxy2025";
PROXY_LOGIN="proxy:supersenha2025";
# Diretorio dos certificados (persistente)
DATADIR=/storage/mitm-proxy;
# Apagar para renovar:
docker rm -f $NAME 2>/dev/null; # < parar e remover container mitm-proxy atual
# Obter imagem, baixar imagem atualizada
docker pull $IMAGE;
# Rodar:
docker run \
-d --restart=always \
--name $NAME \
-h $NAME.intranet.br \
\
--network network_public \
--ip=10.249.254.242 \
\
-v $DATADIR:/data \
\
-p 1080:8080 \
-p 8081:8081 \
\
--label "traefik.enable=true" \
\
--label "traefik.http.routers.${NAME}-admin.rule=Host(\`$FQDN_ADMIN\`)" \
--label "traefik.http.routers.${NAME}-admin.entrypoints=web,websecure" \
--label "traefik.http.routers.${NAME}-admin.tls=true" \
--label "traefik.http.routers.${NAME}-admin.tls.certresolver=letsencrypt" \
--label "traefik.http.routers.${NAME}-admin.service=${NAME}-admin" \
--label "traefik.http.services.${NAME}-admin.loadbalancer.server.port=8081" \
--label "traefik.http.services.${NAME}-admin.loadbalancer.passHostHeader=true" \
\
--label "traefik.http.routers.${NAME}-mitm.rule=Host(\`$FQDN_PROXY\`)" \
--label "traefik.http.routers.${NAME}-mitm.entrypoints=web,websecure" \
--label "traefik.http.routers.${NAME}-mitm.tls=true" \
--label "traefik.http.routers.${NAME}-mitm.tls.certresolver=letsencrypt" \
--label "traefik.http.routers.${NAME}-mitm.service=${NAME}-mitm" \
--label "traefik.http.services.${NAME}-mitm.loadbalancer.server.port=8080" \
--label "traefik.http.services.${NAME}-mitm.loadbalancer.passHostHeader=true" \
\
$IMAGE \
mitmweb \
-p 8080 \
--web-host 0.0.0.0 \
--web-port 8081 \
--set web_password=$ADMIN_PASSWORD \
--set proxyauth=$PROXY_LOGIN \
--set block_global=false \
--set confdir=/data/ca \
--set certs=$FQDN_PROXY=/data/srv/server-bundle.pem \
--ssl-insecure;
echo;
echo "Acesso MITMPROXY:";
echo " ProxyServer.: $FQDN_PROXY";
echo " WebAdmin....: $FQDN_ADMIN";
echo " Arquivos....: $DATADIR";
echo;
Explicação dos argumentos:
- -p: porta interna do container para atendimento dos clientes;
- –web-host: abrir em todos os IPs (dentro do container);
- -set web_password: define a senha de administração;
- –set proxyauth: define o login e senha dos clientes do proxy;
- –set confdir: diretório contendo certificados de CA;
- –set certs: mapeamento de nomes específicos e o arquivo contendo chave+certificado;
- –ssl-insecure: ignorar certificados que não batem com o IP/nome do site;
Testando o proxy com cURL
Considerando o endereço do servidor como, hipoteticamente, proxy.xpto.com na porta tcp/1080 ou pelo ip público, exemplo 45.255.128.2 porta tcp/1080.
Executando testes remotos (em outros computadores ou servidores distantes do servidor Docker):
# Login para usar o proxy:
PROXY_LOGIN="proxy:supersenha2025";
# Usando proxy em canal HTTP para abrir site HTTPs:
curl \
-v \
-m 5 \
-x http://$PROXY_LOGIN@proxy.xpto.com:1080 \
https://anablock.net.br/ipv4.php;
# Usando proxy em canal HTTPs para abrir site HTTPs:
curl \
-v \
-m 5 \
-x http://$PROXY_LOGIN@proxy.xpto.com:1080 \
https://anablock.net.br/ipv4.php;
# Teste sem login: precisa dar acesso negado
# - CONNECT tunnel failed, response 407 Proxy Authentication Required
curl \
-v \
-m 5 \
-x http://proxy.xpto.com:1080 \
https://anablock.net.br/ipv4.php;
Teste de dentro do proprio HOST onde está o Docker com o container
O container está com IP fixo 10.249.254.242
# Login para usar o proxy:
PROXY_LOGIN="proxy:supersenha2025";
# Usando proxy em canal HTTP para abrir site HTTPs:
curl \
-v \
-m 5 \
-x http://$PROXY_LOGIN@10.249.254.242:8080 \
https://anablock.net.br/ipv4.php;
# Usando proxy em canal HTTPs para abrir site HTTPs:
curl \
-v \
-m 5 \
-x http://$PROXY_LOGIN@10.249.254.242:8080 \
https://anablock.net.br/ipv4.php;
# Teste sem login: precisa dar acesso negado
# - CONNECT tunnel failed, response 407 Proxy Authentication Required
curl \
-v \
-m 5 \
-x http://10.249.254.242:8080 \
https://anablock.net.br/ipv4.php;
Acessando administração do MITM-PROXY
Acesse o IP ou nome de DNS do servidor na porta HTTPs 8081, exemplo: https://pxadm.xpto.com ou https://45.255.128.2:80801

Agora teste em um navegador (Firefox por exemplo) e veja todo o conteúdo das requisições http.
6 – MITM Proxy no MacOS
x
x
x
x
x
x
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com
