Saudações. Instruções de 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=tulipa \
--mode reverse:http://n8n:5678;
# Acesso:
echo;
echo "Acesso MITMPROXY:";
echo " WebAdmin.....: $FQDN_MITM";
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.
Criando a unidade certificadora CA
O primeiro passo é criar a CA:
- Chave privada para assinatura digital;
- Certificado auto-assinado da CA;
- Gerar formatos de arquivos para diferentes plataformas (PEM, PKCS-12);
# 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
# Criar CA
CADIR="/storage/mitm-proxy/ca";
# Criar diretorio
mkdir -p $CADIR;
# Entrar no diretorio:
cd $CADIR;
# Gerar chave privada da CA (4096 bits)
[ -f mitm-ca-key.pem ] || \
openssl genrsa -out mitm-ca-key.pem 4096;
# Gerar certificado raiz da CA (válido por 10 anos)
[ -f mitm-ca-cert.crt ] || \
openssl req -new -x509 -days 3650 \
-key mitm-ca-key.pem \
-out mitm-ca-cert.crt \
-subj "/C=$CA_C/ST=$CA_ST/L=$CA_L/O=$CA_O/OU=$CA_OU/CN=$CA_CN";
# Gerar arquivo .pem do certificado com informacoes em texto
[ -f mitm-ca-cert.pem ] || \
(
cat mitm-ca-cert.crt;
openssl x509 -in mitm-ca-cert.crt -text -noout;
) > mitm-ca-cert.pem;
# Bundle da CA (chave + certificado auto-assinado)
[ -f mitmproxy-ca.pem ] || \
(
cat mitm-ca-key.pem; # chave privada
cat mitm-ca-cert.crt; # certificado auto-assinado
# informativo do certificado:
openssl x509 -in mitm-ca-cert.crt -text -noout;
) > mitmproxy-ca.pem;
# Para macOS (formato .p12)
[ -f mitm-ca-cert.p12 ] || \
openssl pkcs12 -export \
-out mitm-ca-cert.p12 \
-inkey mitm-ca-key.pem \
-in mitm-ca-cert.pem \
-passout pass:;
# Para Firefox/outros (formato .cer/.crt)
[ -f mitm-ca-cert.cer ] || \
openssl x509 \
-in mitm-ca-cert.pem \
-out mitm-ca-cert.cer \
-outform DER;
# Arquivo de config OpenSSL para gerar certificado de clientes e servidores
[ -f mitm-openssl.cnf ] || (
echo '';
echo '[req]';
echo 'distinguished_name = req_distinguished_name';
echo 'req_extensions = v3_req';
echo '';
echo '[req_distinguished_name]';
echo '';
echo '[v3_req]';
echo 'basicConstraints = CA:TRUE';
echo 'keyUsage = digitalSignature, keyCertSign, cRLSign';
echo 'subjectKeyIdentifier = hash';
echo 'authorityKeyIdentifier = keyid:always,issuer';
echo '';
echo '[v3_ca]';
echo 'basicConstraints = CA:TRUE';
echo 'keyUsage = digitalSignature, keyCertSign, cRLSign';
echo 'subjectKeyIdentifier = hash';
echo 'authorityKeyIdentifier = keyid:always,issuer';
echo '';
) > mitm-openssl.cnf;
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;
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_ST="Minas Gerais"; # Estado
SRV_L="Nova Lima"; # Cidade
SRV_O="MITM Subsidiary"; # Nome da empresa
SRV_OU="INFRA"; # Nome do departamento
SRV_CN="proxy.intranet.br"; # Nome de DNS do servidor proxy, altere a gosto
# Gerar certificado do servidor proxy MITM
SRVDIR="/storage/mitm-proxy/srv";
mkdir -p $SRVDIR;
cd $SRVDIR;
# Gerar chave privada do certificado intermediário
[ -f server-key.pem ] || \
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/ST=$SRV_ST/L=$SRV_L/O=$SRV_O/OU=$SRV_OU/CN=$SRV_CN";
# Assinar o certificado intermediário com a CA (válido por 10 anos)
[ -f server-cert.crt ] || \
openssl x509 -req \
-in server.csr \
-CA ../ca/mitm-ca-cert.pem \
-CAkey ../ca/mitm-ca-key.pem \
-CAcreateserial \
-out server-cert.crt \
-days 3650 \
-sha256 \
-extfile ../ca/mitm-openssl.cnf \
-extensions v3_ca;
# Gerar arquivo contendo certificado do servidor com informativos
(
# Certificado do servidor
cat server-cert.crt;
# Informativo do certificado:
openssl x509 -in server-cert.crt -text -noout;
) > server-cert.pem;
# Criar fullchain do certificado (servidor + CA)
(
# Certificado do servidor com informativos
cat server-cert.pem;
# Certificado da CA
cat ../ca/mitm-ca-cert.pem;
) > server-fullchain.pem;
# Criar bundle completo (chave + cert + cert ca)
(
cat server-key.pem;
cat server-cert.crt;
cat ../ca/mitm-ca-cert.pem;
) > server-bundle.pem;
# Para Firefox (formato .p12 também funciona)
[ -f server-srv.p12 ] || \
openssl pkcs12 -export \
-out server-srv.p12 \
-inkey server-key.pem \
-in server-cert.crt \
-certfile ../ca/mitm-ca-cert.pem \
-passout pass:;
Cadastrar CA nos clientes
O cadastro da CA auto-assinada nos clientes é necessária para que os certificados gerados pelo MITM-Proxy sejam reconhecidos sem protestos.
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);
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.
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com
