Vous déboguez une application mobile et vous ne comprenez pas quelles requêtes elle envoie au serveur ? Vous devez tester le comportement de l'API dans différentes conditions ou intercepter la réponse et modifier les données à la volée ? mitmproxy résout tous ces problèmes — c'est un outil gratuit et open source qui permet de contrôler complètement le trafic HTTP et HTTPS entre le client et le serveur.
Qu'est-ce que mitmproxy et pourquoi est-il utile pour les développeurs
mitmproxy est un proxy MITM (Man-In-The-Middle) interactif open source, écrit en Python. Il fonctionne comme un intermédiaire entre votre application et le serveur : il intercepte toutes les requêtes et réponses, permet de les visualiser, de les modifier, de les reproduire et de les sauvegarder.
La principale différence entre mitmproxy et les serveurs proxy ordinaires est la capacité à travailler avec le trafic HTTPS chiffré. L'outil génère dynamiquement des certificats SSL pour chaque domaine, ce qui permet de déchiffrer le trafic à la volée, sans perturber le fonctionnement de l'application.
Voici quelques tâches typiques que les développeurs résolvent avec mitmproxy :
- Débogage de l'API — vous voyez les requêtes et réponses exactes, y compris les en-têtes, le corps, les codes de statut.
- Ingénierie inverse — vous analysez comment fonctionnent les applications et services tiers.
- Tests — vous modifiez les réponses du serveur pour vérifier les cas limites.
- Automatisation — vous écrivez des scripts pour modifier le trafic selon des conditions.
- Enregistrement et reproduction — vous sauvegardez une session et la reproduisez sans serveur réel.
- Analyse de sécurité — vous vérifiez si l'application ne transmet pas de données superflues.
Il est important de comprendre
mitmproxy est un outil pour les tests et le développement légaux. Utilisez-le uniquement pour analyser le trafic des applications que vous développez ou que vous avez le droit de tester. Intercepter le trafic d'autrui sans autorisation enfreint la loi.
L'outil est disponible en trois variantes : une interface interactive en console mitmproxy, une interface web mitmweb et un utilitaire en ligne de commande mitmdump. Les trois utilisent un noyau commun et prennent en charge les scripts Python.
Installation de mitmproxy sur Windows, macOS et Linux
mitmproxy peut être installé de plusieurs manières. Nous vous recommandons d'utiliser pip — cela garantit que vous avez la version la plus récente et facilite les mises à jour.
Installation via pip (méthode universelle)
Python 3.9 ou une version plus récente est requis. Vérifiez votre version de Python :
python --version
# ou
python3 --version
Installez mitmproxy :
pip install mitmproxy
Après l'installation, vérifiez :
mitmproxy --version
# Cela devrait afficher : mitmproxy 10.x.x
Installation via des gestionnaires de paquets
macOS (Homebrew) :
brew install mitmproxy
Linux (Ubuntu/Debian) :
sudo apt install mitmproxy
# ou via snap pour la version la plus récente :
sudo snap install mitmproxy
Windows : Téléchargez l'installateur depuis le site officiel mitmproxy.org ou utilisez pip dans PowerShell avec des droits d'administrateur.
Lancement et vérification de base
Par défaut, mitmproxy écoute sur le port 8080. Démarrez l'interface web pour commencer :
# Démarrer l'interface web sur le port 8080
mitmweb
# Démarrer sur un autre port
mitmweb --listen-port 9090
# Interface console
mitmproxy
Après avoir démarré mitmweb, ouvrez votre navigateur à l'adresse http://127.0.0.1:8081 — c'est l'interface web pour visualiser le trafic. Le proxy lui-même fonctionne sur le port 8080.
Configuration des certificats SSL pour l'interception HTTPS
L'interception du trafic HTTPS nécessite l'installation du certificat racine mitmproxy dans le système ou le navigateur. Sans cette étape, le navigateur affichera un avertissement concernant une connexion non sécurisée, et de nombreuses applications refuseront de fonctionner.
Comment cela fonctionne techniquement
Lors du premier démarrage, mitmproxy crée automatiquement un certificat CA racine et le sauvegarde dans le répertoire ~/.mitmproxy/. Lorsque le client se connecte à un site HTTPS via le proxy, mitmproxy génère à la volée un certificat pour ce domaine, le signant avec son CA. Le client fait confiance à ce certificat si le CA est ajouté aux autorités de confiance — et le déchiffrement se fait de manière transparente.
Installation du certificat dans le système
Les certificats se trouvent dans ~/.mitmproxy/ :
mitmproxy-ca-cert.pem— pour Linux/macOSmitmproxy-ca-cert.cer— pour Windowsmitmproxy-ca-cert.p12— pour 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 : Double-cliquez sur le fichier mitmproxy-ca-cert.cer → «Installer le certificat» → «Ordinateur local» → «Autorités de certification racines de confiance».
Installation dans le navigateur Firefox
Firefox utilise son propre magasin de certificats. Allez dans : Paramètres → Confidentialité et sécurité → Certificats → Afficher les certificats → Autorités de certification → Importer. Sélectionnez le fichier mitmproxy-ca-cert.pem et cochez «Faire confiance lors de l'identification des sites web».
Vérification du fonctionnement
Configurez votre navigateur pour utiliser le proxy 127.0.0.1:8080 et ouvrez n'importe quel site HTTPS. Dans l'interface mitmweb, vous devriez voir le trafic déchiffré. Alternativement — ouvrez http://mitm.it via le proxy configuré : mitmproxy affichera les instructions d'installation du certificat pour votre plateforme.
Trois interfaces : mitmproxy, mitmweb et mitmdump
Le package mitmproxy comprend trois utilitaires avec différentes interfaces pour différents scénarios de travail. Comprendre les différences vous aidera à choisir le bon outil pour chaque tâche.
| Utilitaire | Interface | Quand utiliser | Caractéristiques |
|---|---|---|---|
mitmproxy |
TUI en console | Débogage interactif dans le terminal | Nécessite un terminal avec support des couleurs, puissant filtre |
mitmweb |
Navigateur web | Analyse visuelle du trafic | UI conviviale, support des filtres, exportation |
mitmdump |
CLI (stdout) | Scripts, CI/CD, automatisation | Sans interactivité, sortie dans un fichier ou pipe |
Flags utiles pour le lancement
# Enregistrement du trafic dans un fichier
mitmdump -w traffic.dump
# Reproduction du trafic enregistré
mitmdump -r traffic.dump
# Filtrage : uniquement les requêtes vers un domaine spécifique
mitmproxy --filter "~d api.example.com"
# Lancement en mode proxy transparent
mitmproxy --mode transparent
# Lancement comme proxy en amont (chaîne de proxies)
mitmproxy --mode upstream:http://upstream-proxy:8080
# Spécification d'un port spécifique
mitmweb --listen-port 9090 --web-port 9091
# Lancement avec un script
mitmproxy -s my_script.py
Syntaxe des filtres mitmproxy
mitmproxy prend en charge un puissant langage de filtres pour sélectionner les requêtes souhaitées :
# ~d — filtre par domaine
~d api.example.com
# ~u — filtre par URL (regex)
~u /api/v2/users
# ~m — filtre par méthode HTTP
~m POST
# ~s — uniquement les réponses
~s ~c 404
# ~c — filtre par code de statut
~c 500
# Combinaison (ET)
~d api.example.com & ~m POST
# Combinaison (OU)
~c 404 | ~c 500
# NON
!~d static.example.com
Écriture de scripts en Python : interception et modification du trafic
Les scripts sont la principale superpuissance de mitmproxy. Grâce à eux, vous pouvez automatiquement modifier les requêtes et les réponses, enregistrer des données dans le format souhaité, simuler des erreurs de serveur et bien plus encore. Les scripts sont écrits en Python et utilisent un modèle événementiel.
Événements principaux (hooks)
| Hook | Quand il est appelé | Objet |
|---|---|---|
request |
Requête reçue du client | flow.request |
response |
Réponse reçue du serveur | flow.response |
error |
Erreur de connexion | flow.error |
tls_start_client |
Début de la poignée de main TLS avec le client | tls_start |
Exemple 1 : journalisation des requêtes dans un fichier
# logger.py
import mitmproxy.http
import json
from datetime import datetime
def request(flow: mitmproxy.http.HTTPFlow) -> None:
"""Journaliser chaque requête dans un fichier 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:
"""Journaliser les réponses avec un code d'erreur."""
if flow.response.status_code >= 400:
print(f"[ERREUR] {flow.request.method} {flow.request.pretty_url} "
f"-> {flow.response.status_code}")
Lancement du script :
mitmproxy -s logger.py
Exemple 2 : modification des requêtes — substitution des en-têtes
# modify_headers.py
from mitmproxy import http
def request(flow: http.HTTPFlow) -> None:
"""Substituer User-Agent et ajouter un en-tête personnalisé."""
if "api.example.com" in flow.request.pretty_host:
# Substitution de 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"
)
# Ajout d'un en-tête d'autorisation
flow.request.headers["X-Custom-Token"] = "test-token-12345"
# Suppression d'un en-tête
if "X-Debug-Info" in flow.request.headers:
del flow.request.headers["X-Debug-Info"]
Exemple 3 : substitution de la réponse du serveur (mock)
# mock_response.py
from mitmproxy import http
import json
def request(flow: http.HTTPFlow) -> None:
"""Intercepter la requête et retourner une réponse mock, sans contacter le serveur."""
if flow.request.pretty_url.endswith("/api/v1/user/profile"):
# Créer une réponse mock
mock_data = {
"id": 42,
"name": "Test User",
"email": "[email protected]",
"premium": True # Tester la fonctionnalité premium
}
flow.response = http.Response.make(
200, # Code de statut
json.dumps(mock_data), # Corps de la réponse
{"Content-Type": "application/json"} # En-têtes
)
def response(flow: http.HTTPFlow) -> None:
"""Modifier la réponse réelle du serveur."""
if "/api/v1/products" in flow.request.pretty_url:
try:
data = json.loads(flow.response.text)
# Ajouter un champ à chaque produit
for product in data.get("items", []):
product["debug_info"] = "intercepted"
flow.response.text = json.dumps(data)
except (json.JSONDecodeError, KeyError):
pass
Exemple 4 : simulation d'une connexion lente et d'erreurs
# chaos_testing.py
from mitmproxy import http
import time
import random
def response(flow: http.HTTPFlow) -> None:
"""Ingénierie du chaos : délais et erreurs aléatoires pour les tests."""
# Ajouter un délai aléatoire de 0 à 2 secondes
if "api.example.com" in flow.request.pretty_host:
delay = random.uniform(0, 2.0)
time.sleep(delay)
# 10% de probabilité de réponse 503
if random.random() < 0.1:
flow.response = http.Response.make(
503,
json.dumps({"error": "Service Unavailable"}),
{"Content-Type": "application/json"}
)
Interception du trafic des applications mobiles
L'analyse du trafic des applications mobiles est l'une des tâches les plus fréquentes lors de l'utilisation de mitmproxy. Cela est particulièrement utile lors de l'ingénierie inverse des API des applications mobiles ou lors des tests de votre propre application sur un appareil réel.
Configuration sur Android
Étape 1. Assurez-vous que le téléphone et l'ordinateur sont sur le même réseau Wi-Fi.
Étape 2. Lancez mitmproxy sur l'ordinateur :
mitmweb --listen-host 0.0.0.0 --listen-port 8080
Étape 3. Sur Android : Paramètres → Wi-Fi → maintenez le réseau enfoncé → Modifier le réseau → Avancé → Proxy → Manuel. Entrez l'IP de l'ordinateur et le port 8080.
Étape 4. Installation du certificat sur Android : ouvrez un navigateur sur l'appareil, allez sur http://mitm.it et téléchargez le certificat pour Android. Ensuite : Paramètres → Sécurité → Installer le certificat → Certificat CA.
Android 7+ et Certificate Pinning
À partir d'Android 7.0, les applications ne font par défaut pas confiance aux certificats CA personnalisés. Pour intercepter le trafic de ces applications, il faudra soit un accès root, soit modifier le network_security_config.xml dans l'APK. Pour les applications avec SSL Pinning, utilisez Frida ou Xposed Framework pour contourner la vérification du certificat.
Configuration sur iOS
Étape 1. Configurez le proxy de manière similaire à Android : Paramètres → Wi-Fi → appuyez sur (i) à côté du réseau → Configurer le proxy → Manuel.
Étape 2. Ouvrez Safari et allez sur http://mitm.it — téléchargez le certificat pour iOS.
Étape 3. Installez le profil : Paramètres → Profil téléchargé → Installer.
Étape 4. Activez la confiance dans le certificat : Paramètres → Général → À propos → Faire confiance aux certificats — activez le commutateur pour mitmproxy.
Interception du trafic d'une application spécifique via Python
# mobile_app_analyzer.py
from mitmproxy import http
import json
import re
# Domaines de l'application cible
TARGET_DOMAINS = ["api.myapp.com", "cdn.myapp.com"]
def response(flow: http.HTTPFlow) -> None:
"""Analyser le trafic de l'application mobile."""
host = flow.request.pretty_host
if not any(domain in host for domain in TARGET_DOMAINS):
return
# Extraire les réponses 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"Statut: {flow.response.status_code}")
print(f"Réponse: {json.dumps(data, indent=2, ensure_ascii=False)}")
except json.JSONDecodeError:
pass
# Chercher des tokens dans les en-têtes de requête
auth_header = flow.request.headers.get("authorization", "")
if auth_header:
print(f"[AUTH] Token trouvé : {auth_header[:50]}...")
Chaîne de proxies : mitmproxy + proxy en amont
L'un des scénarios puissants est d'utiliser mitmproxy en conjonction avec un serveur proxy externe. Cela permet d'intercepter et d'analyser le trafic (via mitmproxy) tout en le dirigeant à travers une adresse IP externe (via un proxy en amont). Ce schéma est utilisé lors des tests d'API géodépendantes ou lors du développement d'applications qui doivent fonctionner via un proxy.
Mode proxy en amont
# Diriger tout le trafic à travers un proxy HTTP en amont
mitmproxy --mode upstream:http://proxy-host:port
# Proxy SOCKS5 en amont
mitmproxy --mode upstream:socks5://proxy-host:port
# Avec authentification
mitmproxy --mode upstream:http://user:password@proxy-host:port
# Via mitmweb avec en amont
mitmweb --mode upstream:http://proxy-host:port
Dans ce mode, mitmproxy reçoit les requêtes localement, déchiffre le HTTPS, vous permet de les analyser et de les modifier, puis les transmet via un proxy externe. Cela est particulièrement pratique lors des tests d'API accessibles uniquement depuis certaines régions.
Pour de telles tâches, les proxies résidentiels sont bien adaptés — ils ont de vraies adresses IP d'utilisateurs domestiques dans les pays nécessaires, ce qui permet de tester correctement les réponses géodépendantes des API.
Sélection dynamique de proxy en amont dans un script
# dynamic_upstream.py
from mitmproxy import http
from mitmproxy.net.server_spec import ServerSpec
# Liste des proxies pour la rotation
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:
"""Rotation des proxies en amont pour chaque requête."""
global proxy_index
# Diriger les requêtes vers l'API à travers différents 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"Utilisation du proxy : {proxy_url} pour {flow.request.pretty_url}")
Proxy transparent (mode transparent)
En mode transparent, l'application ne sait pas que son trafic est intercepté — il n'est pas nécessaire de configurer le proxy dans les paramètres. Cela nécessite la configuration d'iptables/pf au niveau du système d'exploitation :
# Lancement en mode transparent
mitmproxy --mode transparent --listen-port 8080
# Configuration d'iptables pour rediriger le trafic (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
Scénarios pratiques d'application mitmproxy
Examinons des tâches spécifiques que les développeurs résolvent avec mitmproxy dans des projets réels.
Scénario 1 : Tester l'API sans modifier le serveur
Imaginez : vous devez vérifier comment le frontend traite une réponse avec un tableau de données vide ou une erreur d'autorisation 401, mais il est difficile de reproduire cela sur le serveur de test. mitmproxy permet de modifier la réponse à la volée :
# test_edge_cases.py
from mitmproxy import http
import json
def response(flow: http.HTTPFlow) -> None:
url = flow.request.pretty_url
# Test : liste de produits vide
if "/api/products" in url and "test_empty=1" in url:
flow.response.text = json.dumps({"items": [], "total": 0})
# Test : token expiré
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"}
)
# Test : dépassement de la limite de requêtes
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"}
)
Scénario 2 : Enregistrement et reproduction de session
Utile pour créer des fixtures de test ou démontrer des fonctionnalités sans serveur réel :
# Enregistrement de la session dans un fichier
mitmdump -w session.dump --filter "~d api.example.com"
# Reproduction de la session enregistrée (hors ligne)
mitmdump -r session.dump
# Conversion au format HAR pour analyse
mitmdump -r session.dump --flow-detail 3 > session.txt
Scénario 3 : Documentation automatique de l'API
# api_documenter.py
from mitmproxy import http
import json
from collections import defaultdict
# Dictionnaire pour accumuler des informations sur les endpoints
endpoints = defaultdict(lambda: {"methods": set(), "status_codes": set(),
"request_fields": set(), "response_fields": set()})
def _extract_fields(data, prefix=""):
"""Extraire récursivement les champs du 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
# Normaliser l'URL (supprimer l'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)
# Extraire les champs de la requête
if flow.request.text:
try:
req_data = json.loads(flow.request.text)
ep["request_fields"].update(_extract_fields(req_data))
except json.JSONDecodeError:
pass
# Extraire les champs de la réponse
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():
"""Afficher la documentation à la fin."""
print("\n=== DOCUMENTATION DE L'API ===\n")
for endpoint, info in sorted(endpoints.items()):
print(f"Endpoint : {endpoint}")
print(f" Codes de statut : {sorted(info['status_codes'])}")
if info["request_fields"]:
print(f" Champs de requête : {sorted(info['request_fields'])}")
if info["response_fields"]:
print(f" Champs de réponse : {sorted(info['response_fields'])}")
print()
Scénario 4 : Tester les réponses géodépendantes
Lors du développement d'applications avec du contenu régional, il est important de vérifier comment l'API répond aux requêtes provenant de différents pays. Pour cela, mitmproxy est lancé en mode en amont avec des proxies de datacenter des régions nécessaires — c'est un moyen rapide et fiable de simuler des requêtes depuis des pays spécifiques.
# geo_test.py
from mitmproxy import http
def response(flow: http.HTTPFlow) -> None:
"""Journaliser les en-têtes et données géodépendants."""
# Vérifier quel contenu le serveur retourne
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}")
# Chercher des mentions de devises et de locales dans la réponse
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}")
Scénario 5 : Utilisation de mitmproxy dans CI/CD
mitmdump est idéal pour les tests d'intégration dans un pipeline CI/CD — il est lancé comme un processus en arrière-plan, enregistre le trafic et se termine avec les tests :
#!/bin/bash
# ci_test.sh
# Lancer mitmdump en arrière-plan
mitmdump -w test_traffic.dump -s ci_assertions.py &
MITM_PID=$!
# Donner au proxy le temps de démarrer
sleep 1
# Lancer les tests avec le proxy
export HTTP_PROXY=http://127.0.0.1:8080
export HTTPS_PROXY=http://127.0.0.1:8080
pytest tests/integration/ -v
# Arrêter mitmdump
kill $MITM_PID
# Analyser le trafic enregistré
mitmdump -r test_traffic.dump -s analyze_traffic.py
Le script ci_assertions.py peut vérifier que l'application ne fait pas de requêtes superflues, ne transmet pas de données sensibles en clair et respecte les contrats de l'API.
Scénario 6 : Analyse du trafic du parseur
Lors du développement de parseurs, mitmproxy aide à comprendre quelles requêtes le navigateur effectue lors du chargement de la page — y compris les requêtes XHR/fetch vers l'API qui ne sont pas visibles dans le code source HTML. Cela permet d'accéder directement à l'API du site au lieu de parser le HTML. Lors du développement de telles solutions, on utilise souvent des proxies résidentiels pour la rotation des IP, afin d'éviter les blocages lors de la collecte de données.
Conclusion
mitmproxy est l'un des outils les plus puissants dans l'arsenal des développeurs pour travailler avec le trafic HTTP/HTTPS. Il combine les fonctions de débogueur, d'environnement de test, de documentateur d'API et d'outil d'analyse de sécurité. Les trois interfaces — console, web et CLI — couvrent tous les scénarios : du débogage interactif à l'automatisation dans CI/CD.
```