ProxynetProxynet

¿Qué es un proxy MITM? Guía de Charles, Fiddler y mitmproxy

Publicado:

15 min de lectura

Acar Diveroli
Autor: Acar Diveroli
Paneles de solicitud y respuesta 403 abiertos como un sobre, candado abierto en el hueco, insignia azul de CA local arriba.

Tu scraper recibe un 403 en una página de categoría que en el navegador se abre sin problemas, y el error no dice nada más allá del código de estado. Si pusieras lado a lado la solicitud del navegador y la de Python, verías la diferencia en un minuto, pero HTTPS mantiene las dos selladas. Un proxy MITM en tu propio equipo abre ese sello solo para ti.

Esta guía explica cómo lee HTTPS un proxy MITM, compara Charles, Fiddler y mitmproxy con sus condiciones de licencia de 2026 y trata el certificado raíz, tus propias apps móviles, una configuración de Python probada y el encadenamiento con un proxy upstream. Todo parte de tu propio dispositivo y tu propia app, o de un sistema que tengas permiso por escrito para probar.

¿Qué es un proxy MITM?

«Man-in-the-middle» (intermediario) es el nombre de un ataque: alguien se cuela entre dos partes sin que lo sepan y lee lo que se envían. Un proxy MITM usa esa misma posición para depurar. Tú instalas la herramienta, el tráfico es tuyo y eres tú quien confía en su certificado, así que nadie resulta engañado. Las empresas usan la técnica para la inspección TLS en los equipos de su personal; ese lado corresponde a proxy o firewall.

Un forward proxy normal (cómo funciona un servidor proxy) solo ve el host de destino de una solicitud HTTPS, por la línea CONNECT example.com:443, y después transporta bytes cifrados. Un proxy MITM termina la conexión cifrada en tu máquina, así que ve la URL completa, cada cabecera y el cuerpo.

¿Cómo abre un proxy MITM el tráfico HTTPS?

RFC 9110 describe un túnel como un relé ciego que pasa los mensajes sin modificarlos. Un proxy normal respeta esa regla después de CONNECT; un proxy MITM la rompe a propósito, para los clientes que confían en su certificado. Según la descripción del flujo de mitmproxy:

  1. El cliente envía CONNECT example.com:443 a la herramienta local.
  2. La herramienta responde 200 Connection Established, como si hubiera abierto el túnel.
  3. El cliente inicia el handshake TLS e indica el host en el campo SNI.
  4. La herramienta se conecta a ese host por TLS y lee los nombres (CN y SAN) del certificado del servidor.
  5. Crea un certificado con esos nombres y lo firma con su certificado raíz local (la CA, autoridad de certificación).
  6. Si el cliente confía en esa CA, el handshake se completa y la herramienta lee el tráfico en texto plano antes de volver a cifrarlo hacia el servidor.

Si el cliente no confía en la CA, el paso 6 falla con un error de certificado, como debe ser. Un gateway de Proxynet nunca hace el paso 5: retransmite el túnel CONNECT a ciegas, así que con los Proxies HTTPS no necesitas ningún certificado raíz en tu dispositivo.

Charles, Fiddler y mitmproxy comparados

Según las páginas de los propios fabricantes en septiembre de 2026; solo modelos de licencia, sin precios.

HerramientaLicenciaPlataformasInterfazPuerto por defectoProxy upstreamAutomatización
CharlesLicencia de usuario de pago tras 30 días de pruebaWindows, macOS, LinuxApp de escritorioNormalmente 8888HTTP, HTTPS y SOCKS; autenticación Basic o NTLMBreakpoints, Rewrite, Map Local
Fiddler EverywhereSuscripción, 10 días de pruebaWindows, macOS, LinuxApp de escritorio8866Cadena de proxy manual; autenticación Kerberos, Negotiate o NTLMRules
Fiddler ClassicSolo uso no comercial desde el 3 de agosto de 2026Solo WindowsApp de escritorio8888No se trata aquíFiddlerScript
mitmproxyCódigo abierto, MITWindows, macOS, LinuxTerminal, navegador (mitmweb), línea de comandos (mitmdump)8080--mode upstream: con upstream_auth (Basic)Addons de Python, CI

Charles y Fiddler Everywhere encajan con los equipos de QA móvil que editan solicitudes en una ventana; mitmproxy encaja con los desarrolladores que quieren la comprobación dentro de una suite de pruebas o en CI, donde cada paso es una función de Python. Burp Suite está orientado a las pruebas de seguridad, que quedan fuera de esta guía.

¿Qué es Charles Proxy y cuándo elegirlo?

Charles es una app de escritorio que puedes probar durante 30 días antes de comprar una licencia de usuario. Solo descifra los hosts de su lista SSL Proxying (* significa todos los hosts) y reenvía el resto del tráfico HTTPS sin abrirlo. Un tester apunta el proxy Wi-Fi del iPhone al portátil y al puerto 8888, permite el dispositivo cuando Charles lo pregunta y después usa Breakpoints para editar solicitudes, Map Local para responder desde un archivo y la limitación de ancho de banda (throttling) para imitar una red lenta.

¿Qué es Fiddler? Classic y Everywhere

Fiddler Classic solo funciona en Windows, ya no se desarrolla y tiene FiddlerScript. Desde el 3 de agosto de 2026 su licencia solo permite el uso no comercial; los usuarios comerciales tuvieron hasta el 17 de septiembre de 2026 para migrar, y no existe una licencia de pago de Classic.

Fiddler Everywhere es el producto comercial: Windows, macOS y Linux, una suscripción tras 10 días de prueba, compatibilidad con HTTP/2 y TLS 1.3, y el puerto 8866. Activas la captura HTTPS, confías en su certificado raíz y filtras las sesiones por host.

¿Qué es mitmproxy? Tres interfaces y addons de Python

mitmproxy tiene licencia MIT; la versión 12.2.3 (12 de mayo de 2026) necesita Python 3.12 o posterior. Incluye mitmproxy (vista de terminal), mitmweb (vista en el navegador) y mitmdump (sin interfaz, para scripts y CI), todos en el puerto 8080 por defecto.

En el primer arranque crea su CA en ~/.mitmproxy, única para esa instalación: la clave privada (mitmproxy-ca.pem) está junto a los archivos de certificado de cada plataforma (mitmproxy-ca-cert.pem, .p12, .cer). Con el proxy configurado en un dispositivo, mitm.it ofrece el archivo adecuado y los pasos de instalación. Un addon es un archivo de Python cuyas funciones llevan el nombre de eventos como response.

¿Por qué necesitas un certificado raíz y es seguro?

Quien tiene la clave privada de una CA puede crear un certificado que parece válido para cualquier sitio en todos los dispositivos que confían en ella. El riesgo está en esa clave, no en la herramienta:

  • Solo una CA generada por tu propia herramienta. Nuestra guía sobre la seguridad de los proxies gratis dice que no instales un certificado que te pida un servicio de proxy, y eso sigue en pie: una CA remota permite que un desconocido lea tu tráfico. Una herramienta en tu propio equipo es distinta, porque su clave nunca sale de tu máquina.
  • Solo en dispositivos de prueba, solo durante la prueba. No compartas ~/.mitmproxy ni lo subas a un repositorio, y elimina la CA al terminar.
  • Mantén activas las comprobaciones de la herramienta. La opción ssl_insecure de mitmproxy omite las comprobaciones de certificado hacia el servidor, y su texto de ayuda advierte que eso deja al propio mitmproxy expuesto a una interceptación.

Para eliminar la CA:

  • Windows: certmgr.msc > Entidades de certificación raíz de confianza > Certificados.
  • macOS: borra el certificado de la herramienta en Acceso a Llaveros.
  • iPhone: Ajustes > General > VPN y gestión de dispositivos > el perfil > Eliminar perfil.
  • Android (Pixel): Ajustes > Seguridad y privacidad > Más ajustes de seguridad > Cifrado y credenciales > Credenciales de usuario; en otras marcas cambian los pasos anteriores a los dos últimos.

Ver el tráfico de tu propia app móvil en Android y iPhone

Apunta el proxy Wi-Fi del teléfono a la dirección IP de tu equipo y al puerto de la herramienta, con los ajustes de proxy de Android o los ajustes de proxy del iPhone.

Android. Según la documentación de configuración de seguridad de red, las apps orientadas a Android 7.0 (nivel de API 24) o posterior solo confían por defecto en las CA del sistema, así que tu app puede fallar con un error TLS mientras el navegador funciona. En tu propia app, añade un bloque debug-overrides:

xml
<!-- res/xml/network_security_config.xml -->
<network-security-config>
    <debug-overrides>
        <trust-anchors>
            <certificates src="user" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>

Haz referencia a él con android:networkSecurityConfig="@xml/network_security_config" en el manifiesto. Android ignora el bloque cuando android:debuggable es false, así que una build de release mantiene las reglas de confianza normales.

iPhone. Después de instalar el perfil, activa la confianza total en Ajustes > General > Información > Ajustes de confianza de certificados.

Pinning. Una app que fija certificados (certificate pinning) rechaza el certificado de la herramienta. En tu propia app, ajusta el pinning en la build de pruebas; en la app de otra persona, el pinning es decisión del desarrollador, y esta guía se detiene ahí.

Interceptar, editar y repetir solicitudes

Las tres herramientas te permiten pausar una solicitud y cambiar una cabecera antes de que salga, responder a una solicitud con un archivo local para probar una pantalla de error y volver a enviar una solicitud guardada, de modo que un fallo que aparece una vez al día se pueda repetir cuando quieras. En mitmproxy, -w flows.mitm guarda los flujos y -C flows.mitm los repite. Repite solicitudes solo contra tu propia API o contra un endpoint que tengas permiso para probar, dentro de sus límites de velocidad.

Para la solicitud en segundo plano de una página web basta con DevTools (encontrar la solicitud XHR); la herramienta local es para scripts y apps.

Depurar un scraper de Python con un proxy MITM

Volvamos al 403: pasamos el script por mitmdump, registramos cada respuesta e imprimimos los detalles de la solicitud en cada error. Probado con Python 3.13, mitmproxy 12.2.3 y Requests 2.34.2 (pip install mitmproxy requests).

El addon, debug_addon.py, imprime una línea por respuesta y, en los 4xx y 5xx, las cabeceras que suelen diferir de las de un navegador, si se envió una cookie y el principio del cuerpo:

python
"""Addon de mitmdump: una línea por respuesta, detalles de la solicitud en cada 4xx y 5xx."""
from mitmproxy import http

WATCH = ("User-Agent", "Accept", "Accept-Language", "Accept-Encoding")


def response(flow: http.HTTPFlow) -> None:
    req, resp = flow.request, flow.response
    print(f"{resp.status_code} {req.method} {req.pretty_url}")
    if resp.status_code < 400:
        return
    for name in WATCH:
        print(f"    {name}: {req.headers.get(name, '(not sent)')}")
    print(f"    Cookie: {'sent' if 'Cookie' in req.headers else 'not sent'}")
    body = resp.get_content(strict=False) or b""  # descomprimido si es gzip o br
    print(f"    body: {body[:300].decode('utf-8', 'replace')!r}")

El script, scraper_debug.py, solo usa el proxy cuando DEBUG_PROXY está definida y confía en la CA local mediante verify. La documentación de Requests advierte que verify=False deja la aplicación expuesta a ataques MitM, así que aquí no aparece nunca:

python
"""Descarga páginas con Requests; define DEBUG_PROXY para pasarlas por un mitmdump local."""
import os
import sys
from pathlib import Path

import requests

DEBUG_PROXY = os.environ.get("DEBUG_PROXY")  # p. ej. http://127.0.0.1:8080
MITM_CA = Path.home() / ".mitmproxy" / "mitmproxy-ca-cert.pem"

session = requests.Session()
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
    "Accept-Language": "en-GB,en;q=0.9",
})


def request_options():
    options = {"timeout": (5, 30)}  # (conexión, lectura) en segundos
    if DEBUG_PROXY:
        if not MITM_CA.is_file():
            sys.exit(f"{MITM_CA} not found: start mitmdump once, it creates the CA there.")
        # Se pasa en cada solicitud: HTTPS_PROXY puede sobrescribir un valor de Session.proxies.
        options["proxies"] = {"http": DEBUG_PROXY, "https": DEBUG_PROXY}
        options["verify"] = str(MITM_CA)  # confía en la CA local, nunca verify=False
    return options


def fetch(url):
    try:
        return session.get(url, **request_options())
    except requests.exceptions.SSLError as exc:
        sys.exit(f"TLS check failed for {url}: is {MITM_CA} the CA of the "
                 f"mitmdump that is running?\n{exc}")
    except requests.exceptions.ProxyError as exc:
        sys.exit(f"Debug proxy {DEBUG_PROXY} did not answer: is mitmdump running?\n{exc}")


if __name__ == "__main__":
    for url in sys.argv[1:] or ["https://httpbin.org/headers"]:
        resp = fetch(url)
        print(resp.status_code, url)
        for name, value in resp.request.headers.items():
            print(f"    {name}: {value}")

Arranca mitmdump solo en la dirección de loopback:

bash
mitmdump --listen-host 127.0.0.1 -p 8080 -s debug_addon.py -w flows.mitm

Después ejecuta el script en una segunda terminal (en PowerShell, define antes $env:DEBUG_PROXY = "http://127.0.0.1:8080"):

bash
DEBUG_PROXY=http://127.0.0.1:8080 python scraper_debug.py https://httpbin.org/headers https://httpbin.org/status/403

La ventana de mitmdump mostró esto (sin las líneas de conexión):

text
200 GET https://httpbin.org/headers
403 GET https://httpbin.org/status/403
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
    Accept: */*
    Accept-Language: en-GB,en;q=0.9
    Accept-Encoding: gzip, deflate, br
    Cookie: not sent
    body: ''

Ahora abre la página en un navegador configurado con el mismo proxy. Accept: */* frente al text/html,... del navegador, o una cookie de una página anterior que falta, son hallazgos típicos; lo segundo significa que el script se saltó un paso (Sesiones y cookies en Python). Si el sitio rechaza a propósito a los clientes que no son navegadores, esa es su respuesta: usa su API o pide permiso.

Un archivo de CA equivocado detuvo el script con CERTIFICATE_VERIFY_FAILED y nuestra pista. mitmdump --set server=false -C flows.mitm -s debug_addon.py repitió las dos solicitudes y terminó sin abrir ningún puerto de escucha.

El servidor ve el handshake TLS de la herramienta, no el de tu script, así que un sitio que comprueba huellas TLS puede responder de otra forma mientras la herramienta está activa; compara con una ejecución sin DEBUG_PROXY. Los reintentos ante un 429 están en Códigos de estado HTTP en web scraping, las variables de entorno en Proxy con wget, la rotación en Cómo rotar proxies en Python y la elección de biblioteca en HTTPX, Requests y AIOHTTP.

Probar desde otro país: encadenar la herramienta local a un proxy

Para ver los precios que tu app muestra a un usuario en Alemania, envía el tráfico del dispositivo a la herramienta MITM local (donde se descifra), de ahí a un proxy upstream y después al destino. Con destinos HTTPS, el proxy upstream solo transporta el túnel ya cifrado de nuevo; Proxynet no lo descifra.

mitmproxy. El modo upstream reenvía cada solicitud, y upstream_auth añade autenticación Basic:

bash
mitmdump --listen-host 127.0.0.1 --mode upstream:http://pr.proxynet.io:8000 --set upstream_auth=user:pass -s debug_addon.py

Lo probamos contra un proxy local que exige contraseña. Con una contraseña incorrecta, el script recibió un 502 de mitmdump, y su registro mostró la causa: el upstream rechazó el CONNECT con un 407.

Charles. External Proxies admite direcciones separadas para HTTP, HTTPS y SOCKS, con autenticación Basic o NTLM y una lista de exclusiones con comodines.

Fiddler Everywhere. Settings > Gateway admite una cadena de proxy manual, y la documentación indica Kerberos, Negotiate y NTLM para la autenticación upstream, no un usuario y una contraseña. Con Proxynet, autoriza en su lugar la dirección IP de tu equipo (user:pass y lista de IP autorizadas).

Usa Proxies móviles para una IP de operador móvil o Proxies residenciales para una conexión doméstica; el escenario completo está en nuestra página de pruebas de aplicaciones.

¿Para qué se usa un proxy MITM?

Errores comunes

  • Dejar la CA instalada. Cualquiera que consiga la clave más adelante puede hacerse pasar por cualquier sitio ante ese dispositivo.
  • Publicar código con verify=False. Apunta verify al archivo de la CA.
  • Esperar que una app de Android confíe en una CA de usuario. Las apps de nivel de API 24+ la ignoran fuera de una build de depuración que lo permita.
  • No añadir el host a SSL Proxying en Charles. Ves entradas CONNECT cifradas y ningún contenido.
  • Escuchar en todas las interfaces. Sin --listen-host, mitmdump se enlazó a 0.0.0.0 y :: en nuestra prueba; enlázalo a 127.0.0.1 salvo que tenga que conectarse un teléfono.
  • Compartir archivos de flujos sin cuidado. Contienen cookies y cabeceras.
  • Usar Fiddler Classic en el trabajo después de agosto de 2026. Su licencia es solo para uso no comercial.

Guía de decisión

NecesidadRecomendación
Comparar la solicitud de un scraper con la del navegadormitmproxy con un addon pequeño; verify de Requests apuntando al archivo de la CA
Editar solicitudes en una ventana para QA móvilCharles o Fiddler Everywhere
Fiddler para trabajo comercial en WindowsFiddler Everywhere u otra herramienta, no Fiddler Classic
Tráfico HTTPS de tu propia app de Androiddebug-overrides solo en la build de depuración
Probar tu app como un usuario de otro paísEncadena la herramienta local a un proxy móvil o residencial (pruebas de aplicaciones)
Encontrar la solicitud en segundo plano de una página webLa pestaña Red (Network) de DevTools; no hace falta una herramienta MITM

Preguntas frecuentes

En tu propio dispositivo y tu propia app, o en un sistema que tengas permiso por escrito para probar, es una herramienta de depuración. Leer en secreto el tráfico de otras personas es otra cosa. Sobre el scraping, consulta ¿El web scraping es legal?.

¿Es seguro mitmproxy?

La herramienta es de código abierto y funciona en local. El riesgo es la clave privada de la CA en ~/.mitmproxy: mantenla en privado, instala la CA solo en dispositivos de prueba y elimínala después.

¿Fiddler Classic sigue siendo gratis y en qué se diferencia de Fiddler Everywhere?

Desde el 3 de agosto de 2026, Fiddler Classic solo es gratis para uso no comercial; funciona en Windows y ya no se desarrolla. Fiddler Everywhere es el producto de pago y multiplataforma, compatible con HTTP/2 y TLS 1.3.

¿Hay una alternativa gratis a Charles Proxy?

mitmproxy es de código abierto y funciona en las mismas plataformas; mitmweb le da una vista en el navegador. El propio Charles tiene una prueba de 30 días.

He instalado el certificado en Android, ¿por qué sigue sin aparecer el tráfico de mi app?

Las apps orientadas al nivel de API 24 o posterior solo confían por defecto en las CA del sistema. Permite las CA de usuario en la build de depuración de tu propia app con debug-overrides, y ajusta el pinning en la build de pruebas si la app fija certificados.

¿Qué diferencia hay entre un proxy MITM, un proxy normal y una VPN?

Un proxy normal y una VPN transportan el tráfico cifrado sin leerlo y cambian tu IP de salida (proxy o VPN). Un proxy MITM lo abre en tu equipo y mantiene tu IP, salvo que lo encadenes a un proxy upstream.

En resumen

Un proxy MITM es una herramienta para leer tu propio tráfico, con una CA que se queda en local, es temporal y solo se instala en dispositivos de prueba. Charles y Fiddler Everywhere sirven para trabajar en una ventana; mitmproxy, para scripts y CI. Cuando una prueba tiene que salir desde otro país, encadena la herramienta local a un proxy upstream, empezando por nuestra página de pruebas de aplicaciones.