«En el navegador puedo abrir sitios externos, pero solo la aplicación empresarial no llega a la API externa», «en la máquina de desarrollo funciona, pero en la red del cliente da timeout», «si lo ejecuto manualmente se comunica, pero en cuanto lo convierto en servicio de Windows falla» — en entornos con proxy interno, este tipo de consulta es de lo más habitual.
La mayoría de las veces la causa no es un fallo del servidor proxy ni un error de la aplicación. En Windows existen varios sistemas distintos de lo que llamamos «configuración de proxy», y qué configuración lee cada uno depende de la aplicación (de la pila HTTP que usa) y de la cuenta con la que se ejecuta — esa es la discrepancia. La configuración que lee el navegador, la que lee un servicio y la que lee el HttpClient de .NET pueden ser todas distintas. Basta con tener clara esta estructura para que el diagnóstico de «funciona en el navegador pero…» se vuelva sorprendentemente rápido.
Este artículo está dirigido al personal de sistemas de pequeñas y medianas empresas y a desarrolladores de aplicaciones Windows, y conecta en un solo hilo los tres sistemas de configuración de proxy —WinINET, WinHTTP y variables de entorno—, la configuración automática mediante PAC y WPAD, las diferencias de resolución de proxy entre .NET Framework y .NET (Core en adelante), los proxies con autenticación (407), la inspección TLS y, finalmente, el procedimiento práctico de diagnóstico. Los patrones de creación de HttpClient y el diseño de timeouts en sí se tratan en «No hay que envolver HttpClient en un using», así que este artículo se centra en la resolución del proxy.
1. Ante todo, la conclusión
- La configuración de proxy de Windows no es una sola: hay al menos tres sistemas. ① La configuración por usuario de WinINET (el «Proxy» de la app Configuración = antiguas Opciones de Internet), ② la configuración de máquina de WinHTTP (
netsh winhttp), y ③ las variables de entornoHTTP_PROXY/HTTPS_PROXY. Cuál de ellas se lee lo decide la propia aplicación.12 - El «Proxy» que se ve en la app Configuración es la configuración por usuario de WinINET. Los navegadores y las aplicaciones interactivas la leen, pero los servicios de Windows no. WinINET no admite su uso en servicios; ese papel lo cumple WinHTTP.13
- La causa más frecuente de «funciona manualmente pero no como servicio» es la diferencia de cuenta de ejecución. LocalSystem o una cuenta de servicio no ven el proxy por usuario que el administrador configuró en su propia sesión.34
netsh winhttp set proxyes una configuración estática y no gestiona PAC, detección automática ni autenticación de proxy. Si necesita configurar PAC o WPAD a nivel de máquina, debe usarnetsh winhttp set advproxy.42- El resultado de PAC cambia según la URL. La función
FindProxyForURLde un archivo PAC recibe la URL y el host como argumentos, y devuelve una lista de proxies o una conexión directa (DIRECT). El caso de «ese sitio sí pasa pero esta API concreta no» a veces se debe a una bifurcación del PAC.56 - El HttpClient de .NET (Core en adelante) inicializa el proxy predeterminado en el orden variables de entorno → configuración de proxy de usuario de Windows. Si está definida cualquiera de
HTTP_PROXY,HTTPS_PROXYoALL_PROXY, tiene prioridad sobre la configuración del sistema operativo, lo que puede provocar el incidente de que «alguien dejó olvidada una variable de entorno».7 - El valor predeterminado de .NET Framework es las Opciones de Internet de la cuenta en ejecución, y puede sobrescribirse con
defaultProxyen app.config. La configuración del archivo de configuración tiene prioridad sobre la del sistema.89 - El 407 es un error de autenticación de proxy, distinto del 401 (autenticación del servidor). Los métodos incluyen Negotiate, NTLM y Basic, y en .NET las credenciales se pasan con
DefaultProxyCredentialsoWebProxy.UseDefaultCredentials. Tenga en cuenta que con una cuenta de servicio cambia el contenido de las «credenciales predeterminadas».101112 - Un proxy de inspección TLS solo funciona correctamente si va acompañado de la distribución del certificado de la CA interna. En las máquinas o entornos de ejecución donde no se ha distribuido, se producen errores de validación de certificado. La solución no es desactivar la validación en la aplicación, sino distribuir el certificado al almacén correspondiente.134
Resumido en una frase: cuando diga «he comprobado la configuración de proxy», debe poder indicar siempre cuál de los tres sistemas comprobó y desde qué cuenta — ese es el tema central de este artículo.
2. Windows tiene tres sistemas de «configuración de proxy»
Empecemos por el mapa general. Las rutas por las que una aplicación en Windows encuentra el proxy interno se dividen a grandes rasgos en estos tres sistemas.
| Sistema de configuración | Ubicación/comando | Ámbito | Quién lo lee principalmente |
|---|---|---|---|
| ① WinINET (Opciones de Internet) | App Configuración → Red e Internet → Proxy, inetcpl.cpl |
Por usuario (predeterminado) | Navegadores, apps de escritorio interactivas, valor predeterminado de .NET Framework |
| ② WinHTTP (configuración de máquina) | netsh winhttp set proxy / set advproxy |
Máquina | Servicios de Windows, parte de los componentes del SO |
| ③ Variables de entorno | HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY |
Proceso (heredado según el origen de definición) | HttpClient de .NET (Core en adelante), curl, herramientas multiplataforma como Node.js o Python |
① es lo que en general se conoce como «la configuración de proxy de Windows»; en realidad es la configuración de WinINET. Históricamente son las Opciones de Internet de Internet Explorer, y por defecto se guardan por usuario.4
② es el valor predeterminado a nivel de máquina para contextos como los servicios, donde «no hay un usuario con sesión iniciada». ③ procede sobre todo de la convención de herramientas multiplataforma, y en Windows también la leen .NET (Core en adelante), curl y similares.7
Lo importante es que quién decide qué sistema se lee no es la configuración, sino la aplicación. Si la aplicación usa WinINET internamente, se lee ①; si usa WinHTTP, ② (o una especificación propia de la app); si es .NET (Core en adelante), el orden es ③→①. Por eso, en muchos casos la realidad no es «la configuración de proxy es correcta pero no conecta», sino «el sistema que lee la aplicación es distinto del que usted comprobó».
Además, al habilitar la directiva de grupo «Configurar el uso del proxy por equipo en lugar de por usuario», ① pasa a ser por máquina y puede aplicar la misma configuración a todos los usuarios. Con MDM (Intune, etc.) puede configurarse por dispositivo mediante el CSP NetworkProxy.4
3. WinINET y WinHTTP — para aplicaciones interactivas y para servicios
3.1. Diferencias de función
WinINET y WinHTTP son ambas pilas de cliente HTTP estándar de Windows, pero están pensadas para usos distintos.
- WinINET: pensada para aplicaciones de escritorio interactivas. Hereda automáticamente las Opciones de Internet del usuario (proxy, cookies, caché de credenciales) y, si es necesario, puede mostrar una interfaz para introducir credenciales. Sin embargo, no admite su uso en servicios ni en procesos de tipo servicio.1
- WinHTTP: pensada para servicios y el lado servidor. Admite ejecución con cuenta de servicio, suplantación (impersonation) de subprocesos y separación de sesiones, a cambio de no compartir la configuración del navegador del usuario, sus cookies ni sus credenciales. Tampoco muestra interfaz.3
La propia guía de Microsoft es clara: «use WinINET salvo que se ejecute dentro de un servicio, o en un proceso de tipo servicio que necesite separación de sesiones y suplantación»; dicho de otro modo, si es un servicio, use WinHTTP.1
3.2. Operaciones básicas de netsh winhttp
El proxy predeterminado de máquina de WinHTTP se gestiona con netsh.2
:: Mostrar la configuración actual del proxy de WinHTTP
netsh winhttp show proxy
:: Configurar un proxy estático (con lista de exclusión)
netsh winhttp set proxy proxy-server="proxy.example.co.jp:8080" bypass-list="*.example.co.jp;<local>"
:: Importar la configuración de las Opciones de Internet (WinINET)
netsh winhttp import proxy source=ie
:: Volver al valor predeterminado (DIRECT)
netsh winhttp reset proxy
Aquí hay dos restricciones que conviene tener presentes.
netsh winhttp set proxyes una configuración estática. No gestiona la detección automática de proxy, ni la especificación de una URL de PAC, ni la autenticación de proxy.4import proxy source=iesolo copia la configuración estática en ese instante, y no sigue los cambios posteriores en las Opciones de Internet. Si necesita una configuración a nivel de máquina que incluya PAC o detección automática, configure el detalle en formato JSON (Proxy,ProxyBypass,AutoconfigUrl,AutoDetect) connetsh winhttp set advproxy.2
3.3. La trampa más frecuente: los servicios no leen la configuración de IE del usuario
El patrón más habitual en el terreno, en orden cronológico, es este:
- El desarrollador ejecuta la herramienta en su propio PC → funciona porque se aplica su configuración de proxy por usuario (①)
- En producción se hace residente como un servicio de Windows bajo LocalSystem
- La configuración visible desde LocalSystem es otra distinta (no ve la configuración por usuario, y la configuración de máquina de WinHTTP está sin configurar = DIRECT) → intenta conectar directamente con la API externa y da timeout
No es que «siendo la misma máquina no funcione»: incluso en la misma máquina, si cambia la cuenta de ejecución, cambia la configuración de proxy visible. Para los procesos que se comunican sin que haya un usuario con sesión iniciada, lo correcto es preparar la configuración a nivel de máquina en la forma que realmente lea la pila HTTP de ese proceso. En aplicaciones nativas o componentes de Windows que usan WinHTTP, la configuración de WinHTTP vía netsh sí surte efecto.4 En cambio, el HttpClient de .NET (Core en adelante) no lee la configuración de máquina de WinHTTP (ver capítulo 5), por lo que en servicios .NET hay que definir variables de entorno del sistema (HTTPS_PROXY, etc.) o especificar explícitamente HttpClientHandler.Proxy desde la configuración de la app.
También hay incidentes en el sentido contrario. Si en un portátil que va y viene entre la red interna y el exterior se «graba» un proxy estático con netsh winhttp set proxy, fuera de la oficina no podrá alcanzar ese proxy y la comunicación fallará por completo. Considere la configuración estática de máquina como un recurso adecuado para servidores cuya configuración de red no cambia.4
4. PAC y WPAD — qué hay detrás de la «configuración automática»
4.1. El archivo PAC y FindProxyForURL
Un archivo PAC (Proxy Auto-Configuration) es JavaScript (ECMAScript) que calcula «qué proxy usar para esta URL», y siempre incluye una función FindProxyForURL(url, host). Esta función devuelve una lista de proxies a usar, o bien indica mediante un valor de retorno especial (DIRECT) que puede conectarse directamente sin proxy.5
function FindProxyForURL(url, host) {
// Los dominios internos y las direcciones privadas van directos
if (dnsDomainIs(host, ".example.co.jp") ||
isInNet(host, "10.0.0.0", "255.0.0.0")) {
return "DIRECT";
}
// El resto va por proxy. Si el primero no está disponible, recurre al siguiente
return "PROXY proxy1.example.co.jp:8080; PROXY proxy2.example.co.jp:8080; DIRECT";
}
De aquí se derivan dos consecuencias prácticas.
- La resolución de proxy debe hacerse por cada URL. Como PAC puede devolver un proxy distinto o una conexión directa según la URL (el host), la función de proxy automático de WinHTTP también está diseñada para consultar cada vez pasando la URL del destino de la petición.6 Que «en el navegador se vea otro sitio» no demuestra que la API problemática pase por la misma ruta.
- DIRECT es una instrucción de «ve sin proxy». Si una comunicación que debería ir hacia la red interna no aparece en los registros del proxy, sospeche primero de que el PAC esté devolviendo DIRECT (o de que coincida con la lista de exclusión).
4.2. Detección automática mediante WPAD
Al activar «Detectar la configuración automáticamente», se busca la ubicación del archivo PAC mediante el protocolo WPAD (Web Proxy Auto-Discovery). En una configuración habitual, o bien DHCP reparte la URL del PAC, o bien se resuelve por DNS un host llamado wpad y se descarga el PAC desde una URL como http://wpad/wpad.dat.14
Es decir, la «detección automática» no es magia: solo funciona en redes donde se ha preparado de antemano el mecanismo de WPAD en DHCP/DNS. En una red sin ese mecanismo, activar solo la detección automática únicamente añade tiempo de espera por el fallo de la detección.
4.3. Comportamiento de los clientes que no pueden leer PAC
No todos los clientes pueden evaluar un PAC.
- La configuración estática de
netsh winhttp set proxyno evalúa PAC.4 - Las herramientas basadas en la variable de entorno
HTTP_PROXYsolo admiten, por norma general, una URL de proxy fija (no hay lugar donde escribir una URL de PAC).7 - En el caso de aplicaciones nativas que usan WinHTTP directamente, el comportamiento depende de cómo se abrió la sesión. Una app que abre la sesión con
WinHttpOpenespecificandoWINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY(Windows 8.1 en adelante) hace que el propio WinHTTP resuelva automáticamente, en cada petición, la configuración de proxy del sistema o del usuario (incluyendo WPAD/PAC).15 En cambio, si se abre con el tradicionalWINHTTP_ACCESS_TYPE_DEFAULT_PROXY(obsoleto desde 8.1), el proxy automático no está integrado en la pila HTTP, y la aplicación debe llamar ella misma aWinHttpGetProxyForUrly aplicar el resultado a la petición. Es decir, en aplicaciones con una implementación antigua puede que el PAC exista pero no se use.5
«El navegador va correctamente al proxy gracias al PAC, pero la aplicación empresarial no lee el PAC e intenta conectar directamente, y falla» — esta también es una discrepancia clásica. En redes que operan con PAC, hay que decidir de antemano un mecanismo de reserva (configuración estática o variables de entorno) para los clientes que no pueden leer el PAC.
5. Resolución de proxy en .NET — distinta en Framework y en .NET (Core en adelante)
Qué configuración de proxy lee una aplicación .NET tiene valores predeterminados distintos en .NET Framework y en .NET (Core en adelante). Confundir esto lleva a investigar una app de .NET 8 con los conocimientos de la época de Framework y equivocarse.
5.1. .NET Framework — el valor predeterminado son las Opciones de Internet, sobrescribible con defaultProxy
En .NET Framework, HttpWebRequest (y el HttpClient que se apoya en él) usan el proxy predeterminado salvo que se especifique Proxy explícitamente. Ese proxy predeterminado se determina combinando la configuración de Internet del sistema (la configuración WinINET de la cuenta en ejecución) y el archivo de configuración, y la configuración del archivo de configuración tiene prioridad.8
El elemento system.net/defaultProxy de app.config (o machine.config) permite controlar este valor predeterminado.9
<configuration>
<system.net>
<!-- useDefaultCredentials: indica si se envían las credenciales predeterminadas a un proxy con autenticación -->
<defaultProxy enabled="true" useDefaultCredentials="true">
<proxy usesystemdefault="true"
proxyaddress="http://proxy.example.co.jp:8080"
bypassonlocal="true" />
<bypasslist>
<add address="[a-z]+\.example\.co\.jp$" />
</bypasslist>
</defaultProxy>
</system.net>
</configuration>
Si se deja el elemento defaultProxy vacío, se usa la configuración del sistema (Opciones de Internet); si se escribe proxyaddress u otros atributos, esos tienen prioridad. Desde el código, el mismo valor predeterminado puede sustituirse con WebRequest.DefaultWebProxy.98
Aquí vuelve a aplicar la trampa de la sección 3.3. Como el valor predeterminado son «las Opciones de Internet de la cuenta en ejecución», una aplicación .NET Framework que se ejecuta con una cuenta de servicio lee una configuración distinta (normalmente vacía) de la que ve el administrador en su escritorio.
5.2. .NET (Core en adelante) — primero las variables de entorno, después la configuración de usuario del sistema operativo
El HttpClient de .NET (Core en adelante) tiene una propiedad estática HttpClient.DefaultProxy. Salvo que el controlador especifique explícitamente un proxy, todas las instancias de HttpClient la usan. La regla de inicialización en Windows es «leer primero las variables de entorno, y si no están definidas, leer la configuración de proxy del usuario».7
Las variables de entorno usadas son las siguientes.7
| Variable de entorno | Significado |
|---|---|
HTTP_PROXY |
Proxy usado para peticiones HTTP |
HTTPS_PROXY |
Proxy usado para peticiones HTTPS |
ALL_PROXY |
Valor de reserva si las anteriores no están definidas |
NO_PROXY |
Lista, separada por comas, de hosts que no deben pasar por proxy |
Hay tres puntos a tener en cuenta.
- Si está definida cualquiera de
HTTP_PROXY,HTTPS_PROXYoALL_PROXY, tiene prioridad sobre la configuración de proxy del sistema operativo. Definir soloNO_PROXYno configura ningún proxy por variable de entorno, y en Windows se sigue usando la configuración de proxy de usuario del sistema operativo. En comprobaciones pasadas, dejarHTTPS_PROXYolvidada en las variables de entorno del sistema, o que una plantilla de CI/CD la inyecte, son terreno abonado para incidentes por «configuración invisible». NO_PROXYno admite comodines (*). Para hacer coincidir subdominios, se antepone un punto (.example.comcoincide conwww.example.compero no conexample.comen sí).7- Fuera de Windows (contenedores Linux, etc.), si las variables de entorno no están definidas, se inicializa sin proxy. Que el comportamiento predeterminado cambie entre Windows y Linux aun con la misma aplicación es algo que conviene revisar al migrar a contenedores.7
5.3. Especificación explícita — HttpClientHandler.Proxy y UseProxy
En ambos entornos de ejecución, la máxima prioridad es la especificación explícita en el controlador. Especificar HttpClientHandler.Proxy tiene prioridad sobre la configuración del sistema operativo y del archivo de configuración, y UseProxy = false hace que no se use proxy en absoluto.14
using System.Net;
// Usar explícitamente el proxy leído desde la configuración de la app
var handler = new HttpClientHandler
{
Proxy = new WebProxy("http://proxy.example.co.jp:8080")
{
BypassProxyOnLocal = true,
BypassList = new[] { @"^intra\.example\.co\.jp$" },
UseDefaultCredentials = true // Si el proxy requiere autenticación, responde con las credenciales de la cuenta en ejecución
},
UseProxy = true
};
var client = new HttpClient(handler);
// Cliente que no usa proxy en absoluto (para conectar directo a APIs internas)
var directHandler = new HttpClientHandler { UseProxy = false };
var directClient = new HttpClient(directHandler);
Cuando no hay especificación explícita y se sigue la configuración del sistema operativo, existen reglas para la exclusión automática de destinos locales. Nombres planos sin puntos, direcciones de loopback y destinos que coinciden con el sufijo de dominio de la propia máquina pueden considerarse «locales».14 Fenómenos como «apuntando directamente a la IP el comportamiento cambia» o «al pasar a FQDN de repente empieza a pasar por el proxy» a veces se deben a esta lógica de decisión.
Ordenando las prioridades queda así:
| Prioridad (alta→baja) | .NET Framework | .NET (Core en adelante) |
|---|---|---|
| 1 | Especificación explícita en HttpClientHandler.Proxy, etc. |
Igual |
| 2 | defaultProxy de app.config |
Asignación a HttpClient.DefaultProxy |
| 3 | Opciones de Internet de la cuenta en ejecución | Variables de entorno (HTTP_PROXY, etc.) |
| 4 | — | Configuración de proxy de usuario de Windows |
6. Proxies con autenticación — el 407 es un error de autenticación «del proxy»
6.1. No confundir 407 con 401
Cuando se intenta atravesar un proxy que exige autenticación, este devuelve el código de estado 407 (Proxy Authentication Required) junto con una cabecera Proxy-Authenticate que enumera los métodos de autenticación disponibles. Es algo distinto de la petición de autenticación del servidor de destino (401 y WWW-Authenticate): cambia tanto a quién se envían las credenciales como dónde se configuran.10
Entre los métodos de autenticación está Basic, que envía el nombre de usuario y la contraseña tal cual, y los de tipo desafío-respuesta como Negotiate (Kerberos/NTLM). En los métodos de desafío-respuesta la contraseña en sí no circula por la red, y la autenticación se completa mediante varios intercambios.10 El mecanismo por el que se «cae» a uno u otro método se trata en detalle en «NTLM y Kerberos explicados con diagramas».
6.2. Cómo pasar credenciales en .NET
Si quiere usar el proxy predeterminado procedente de la configuración del sistema operativo pero solo resolver la autenticación, use HttpClientHandler.DefaultProxyCredentials. Son las credenciales que se envían a ese proxy predeterminado cuando UseProxy = true y Proxy = null (= proxy predeterminado del sistema).11
using System.Net;
var handler = new HttpClientHandler
{
UseProxy = true, // Valor predeterminado. Combinado con Proxy = null, usa el proxy predeterminado del sistema
Proxy = null,
// Responde al 407 con las credenciales de la cuenta en ejecución (usuario con sesión iniciada o cuenta de servicio)
DefaultProxyCredentials = CredentialCache.DefaultCredentials
};
var client = new HttpClient(handler);
Si se especifica el proxy explícitamente, las credenciales se asignan al propio WebProxy. En muchos escenarios de cliente se recomienda usar las credenciales predeterminadas del usuario con sesión iniciada en lugar de un usuario y contraseña individuales; para eso está WebProxy.UseDefaultCredentials = true.12
6.3. El problema del 407 con cuentas de servicio
Aquí también entra en juego la cuenta de ejecución. Las «credenciales predeterminadas» son las credenciales de la cuenta que ejecuta ese proceso. Si se ejecuta con un usuario interactivo, la autenticación frente al proxy se hace como ese usuario; si se ejecuta como servicio bajo LocalSystem, se hace como la cuenta de equipo.
- Si el proxy autentica usuarios mediante integración con Active Directory, no puede autenticar cuentas de equipo ni cuentas locales, y el 407 persiste en cuanto la app pasa a ser un servicio
- Por el contrario, hay entornos donde el proxy tiene preparadas exclusiones de autenticación para servicios (por IP de origen o por cuenta)
Es decir, la investigación del 407 no se cierra solo con «la configuración de la app»: va de la mano de una confirmación de diseño de infraestructura sobre si el proxy puede autenticar la cuenta de ejecución. En las aplicaciones que se conviertan en servicio conviene decidir en la fase de diseño una de estas opciones: ejecutar con una cuenta de servicio de dominio (gMSA, etc.), establecer una exclusión de autenticación en el lado del proxy, o levantar un proxy de retransmisión interno que no requiera autenticación.
También existe la posibilidad de incrustar credenciales en la variable de entorno, como HTTP_PROXY=http://user:pass@proxy:80807, pero como la contraseña en texto plano queda expuesta en las variables de entorno (= información del proceso), no se recomienda para un uso permanente.
7. HTTPS y el proxy — el túnel CONNECT y la inspección TLS
7.1. HTTPS atraviesa el proxy mediante un «túnel»
Cuando se usa un proxy en una comunicación HTTPS, el cliente primero envía al proxy una petición CONNECT host_de_destino:443, y el proxy abre un túnel TCP. Si tiene éxito, el proxy devuelve 200, y a partir de ahí el cliente y el servidor de destino realizan el handshake TLS dentro de ese túnel. Si el túnel no llega a abrirse, el proxy devuelve 407 (solicitud de autenticación), 502 u otros códigos.16
En este modelo, el proxy no puede leer el contenido del túnel (HTTPS cifrado). En los registros del proxy solo quedan el nombre de host de destino y el resultado de la conexión, sin ver la ruta de la URL — este es el comportamiento de un proxy de tipo «paso directo».
7.2. Proxies con inspección TLS y errores de certificado
Por otro lado, entre los productos de seguridad existen proxies del tipo inspección TLS (descifrado SSL, break and inspect), que terminan el TLS una vez, inspeccionan el contenido y lo vuelven a cifrar para reenviarlo. En este esquema, el certificado de servidor que se presenta al cliente no es el auténtico, sino que se sustituye por un certificado re-firmado por la propia CA del proxy.13
Por tanto, la premisa para que este esquema funcione es que «el certificado de CA del proxy esté distribuido en las entidades de confianza de todos los clientes». En máquinas donde no se ha distribuido, o en entornos de ejecución que no consultan el almacén de certificados de Windows (herramientas con su propio almacén de confianza), se producirá un error de validación de certificado. En .NET, esto suele manifestarse como una HttpRequestException con una AuthenticationException interna (con un mensaje del tipo «el certificado remoto no es válido»).
Los principios de actuación son los siguientes.
- Distribuya el certificado de la CA interna al almacén «Entidades de certificación raíz de confianza» del equipo local. Para el criterio de uso entre almacén de usuario y de equipo, consulte «Guía práctica del almacén de certificados de Windows».
- No desactive la validación de certificados en el código. Un
ServerCertificateCustomValidationCallbackque siempre devuelva true, en el momento en que la app salga a una red externa, la convierte en una aplicación vulnerable incapaz de detectar un ataque de intermediario. - Las comunicaciones con anclaje de certificado (pinning) directamente no pueden inspeccionarse. En conexiones ancladas, como las de componentes de Windows que validan un certificado específico de Microsoft, en el momento en que el proxy sustituye el certificado la conexión falla sin más alternativa, y hace falta una exclusión.4 Para el tráfico dirigido a SaaS como Microsoft 365, la propia Microsoft recomienda excluirlo del descifrado e inspección en la capa de red.13
Ante el síntoma de «puedo ver todos los sitios internos, pero solo un servicio en la nube concreto da error de certificado en la app», sospeche primero de la combinación entre la lista de exclusión de la inspección TLS y el anclaje de certificado.
8. Procedimiento de diagnóstico — identificar al culpable en 5 pasos
La investigación de «no conecta» avanza de forma mecánica en este orden.
| Paso | Qué hacer | Qué se averigua |
|---|---|---|
| ① Reproducir | Acceder a la URL problemática con curl.exe -v o Invoke-WebRequest (a ser posible con la misma máquina y la misma cuenta) |
Si es un problema propio de la app o del entorno |
| ② Recoger configuración | Recoger los tres sistemas: netsh winhttp show proxy, configuración por usuario y variables de entorno |
Qué hay definido en cada sistema |
| ③ Identificar la cuenta | Identificar la cuenta de ejecución de la app en cuestión (servicio, Programador de tareas, otro usuario) | Con qué configuración y qué credenciales se ejecuta |
| ④ Clasificar el error | Distinguir entre 407 / 403 / fallo de resolución de nombres / timeout / error de certificado | Diagnóstico entre autenticación de proxy, denegación de política, ruta o inspección TLS |
| ⑤ Registros del proxy | Comprobar la hora correspondiente en los registros de acceso del servidor proxy | Si la petición llegó siquiera al proxy y con qué identidad se autenticó |
La recogida del paso ② puede hacerse toda junta con PowerShell.
# ① Configuración por usuario (WinINET) — atención: lee el HKCU de la cuenta en ejecución
Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable, ProxyServer, ProxyOverride, AutoConfigURL
# ② Configuración de máquina (WinHTTP)
netsh winhttp show proxy
# ③ Variables de entorno
Get-ChildItem env: | Where-Object Name -match 'proxy'
Hay algunos consejos prácticos.
- En la prueba de reproducción de ①, tenga presente qué sistema de configuración lee la herramienta. El
curl.exeque viene con Windows permite especificar el proxy explícitamente con-x http://proxy:8080, y para la validación TLS normalmente usa el almacén de certificados del sistema operativo (Schannel). ElInvoke-WebRequestde Windows PowerShell 5.1 sigue la resolución del lado .NET Framework (por defecto, Opciones de Internet), y en PowerShell 7 sigue la del lado .NET (con prioridad para las variables de entorno). El propio hecho de que «curl pasa pero la app no» ya es una pista de discrepancia entre sistemas de configuración. - Si en ③ el objetivo es un servicio, vuelva a comprobar ① y ② con la misma cuenta que el servicio. Comprobarlo en la propia sesión del administrador no demuestra cómo lo ve LocalSystem.
- En la clasificación de errores de ④, tome como primera candidata el capítulo 6 (autenticación) si es 407, el capítulo 7 (inspección TLS) si es un error de certificado, y en caso de timeout, «no se ha llegado a alcanzar el proxy» (ruta, resolución de nombres, firewall). El patrón en el que la causa no es el proxy sino las reglas de entrada del Firewall de Windows se trata en «El Firewall de Windows y las aplicaciones empresariales».
- Si al llegar al paso ⑤ no hay rastro en los registros del proxy, la comunicación no llegó al proxy. Sospeche de una decisión DIRECT del PAC, de la lista de exclusión o de una variable de entorno olvidada, y si es necesario confirme el destino real con una captura de paquetes («Captura de paquetes en Windows en la práctica — cuándo usar pktmon, netsh trace y Wireshark»).
9. Recomendaciones de diseño — hacer que la app «pueda configurar» el proxy
Si se le da la vuelta al procedimiento de investigación, se obtienen pautas de diseño para el lado de la aplicación. En aplicaciones Windows que se entreguen para un entorno con proxy interno, se recomienda lo siguiente.
- Hacer que el proxy se pueda especificar explícitamente en la configuración de la app, con el valor predeterminado «seguir la configuración del SO». En muchos entornos basta con el valor predeterminado, y solo en entornos excepcionales —donde no se pueda leer el PAC, se ejecute como servicio o haya una configuración de proxy peculiar— conviene poder indicar en un archivo de configuración la URL del proxy, la lista de exclusión y la opción de «no usar proxy». El punto de implementación es
HttpClientHandler.Proxy/UseProxyde la sección 5.3.14 - Documentar explícitamente el tratamiento de excepción de proxy para las comunicaciones internas (API, base de datos, servidor de licencias, etc.). Deje en forma consultable en el manual de implantación con cuál de estos se excluye: el DIRECT del PAC, la lista de exclusión o
NO_PROXY. Como la regla de coincidencia deNO_PROXY(sin comodines, el significado del punto inicial) se malinterpreta con frecuencia, añada ejemplos.7 - Diseñar los timeouts y los reintentos partiendo de que hay un proxy de por medio. Si el proxy está caído o se ha quedado bloqueado en la autenticación, una implementación que espere el timeout largo predeterminado bloquea tanto la interfaz como la operación. Separe un timeout de conexión más corto, y limite los reintentos a peticiones idempotentes (los detalles de diseño están en «No hay que envolver HttpClient en un using»).
- Dejar registrado en el log «qué proxy se usó». Haga que la propia aplicación pueda responder a la primera pregunta de una investigación de incidencias.
Para el punto 4, basta con registrar el resultado de la resolución como se muestra a continuación para que sea efectivo. La clave es derivar la ruta a partir de la configuración que realmente configuró al cliente (el controlador). Si se registra HttpClient.DefaultProxy directamente en el log, cuando el controlador haya especificado Proxy explícitamente o se haya puesto UseProxy = false, quedará registrado un valor que no coincide con la ruta real.
using System.Net.Http;
// handler es la misma instancia usada para crear el HttpClient
// Si UseProxy=false, siempre va directo. Si hay una especificación explícita se usa esa; si no, se usa DefaultProxy
var effectiveProxy = handler.UseProxy
? handler.Proxy ?? HttpClient.DefaultProxy
: null;
var target = new Uri("https://api.example.com/v1/orders");
var route = effectiveProxy is null || effectiveProxy.IsBypassed(target)
? "DIRECT"
: effectiveProxy.GetProxy(target)?.ToString() ?? "DIRECT";
logger.LogInformation("Envío HTTP {Target} ruta {Route} cuenta de ejecución {User}",
target, route, Environment.UserName);
Si al arrancar se registra una vez, para los destinos principales, la «ruta» y la «cuenta de ejecución», los pasos ①-③ del diagnóstico del capítulo 8 se resuelven solo con mirar el log. Que, ante un «funciona en el navegador pero…», la propia aplicación pueda decir «yo usé esta configuración y esta ruta» es la condición de una aplicación resistente a los problemas de proxy.
10. Resumen
- La configuración de proxy de Windows se divide en tres sistemas —configuración por usuario de WinINET, configuración de máquina de WinHTTP y variables de entorno—, y cuál se lee depende de la aplicación (de su pila HTTP) y de la cuenta de ejecución.
- WinINET está pensada para aplicaciones interactivas y no admite su uso en servicios; ese papel lo cumple WinHTTP (
netsh winhttp). Ante «funciona manualmente pero no como servicio», sospeche primero de la diferencia de cuenta de ejecución. netsh winhttp set proxyes una configuración estática que no gestiona PAC, detección automática ni autenticación. En redes que operan con PAC hay que decidir de antemano cómo tratar a los clientes que no pueden leerlo.- El
FindProxyForURLdel PAC devuelve un proxy o DIRECT según la URL. WPAD solo funciona en redes que tienen preparado el mecanismo de DHCP/DNS. - El valor predeterminado de .NET Framework son las Opciones de Internet de la cuenta de ejecución (sobrescribible con
defaultProxy), y en .NET (Core en adelante) el orden es variables de entorno → configuración de proxy de usuario. La especificación explícita (HttpClientHandler.Proxy) siempre tiene la máxima prioridad. - El 407 es un error de autenticación de proxy, y en aplicaciones que se ejecutan con cuenta de servicio, una causa típica es que las «credenciales predeterminadas» pasan a ser las de otra identidad.
- Un proxy de inspección TLS presupone la distribución del certificado de CA interna, y la solución correcta ante un error de certificado no es desactivar la validación, sino distribuir el certificado al almacén. Las comunicaciones con anclaje de certificado requieren una exclusión.
- El diagnóstico se hace de forma mecánica en el orden «reproducir → recoger la configuración de los tres sistemas → identificar la cuenta de ejecución → clasificar el error → registros del proxy». Del lado de la aplicación, lo mejor como prevención es diseñarla de modo que «pueda configurar el proxy y deje en el log la ruta que usó».
La próxima vez que le consulten «solo la app empresarial no conecta», empiece preguntando esto:
Esa aplicación, ¿con la cuenta de quién se ejecuta, y de cuál de los tres sistemas de proxy lee la configuración?
Con esta sola pregunta, el punto de partida de la investigación cambia por completo.
Artículos relacionados
- No hay que envolver HttpClient en un using — la comunicación HTTP en aplicaciones empresariales C# en la práctica (patrones de creación, timeouts, reintentos)
- Captura de paquetes en Windows en la práctica — cuándo usar pktmon, netsh trace y Wireshark
- El Firewall de Windows y las aplicaciones empresariales — registre las reglas de entrada desde el instalador
- Cómo crear y operar un servicio de Windows — del Programador de tareas a convertir un BackgroundService en servicio
- NTLM y Kerberos explicados con diagramas — por qué la autenticación «cae» a NTLM
- Guía práctica del almacén de certificados de Windows — usuario o equipo, dónde instalarlo
Áreas de consultoría relacionadas
KomuraSoft LLC atiende consultas sobre investigación de problemas de comunicación en aplicaciones Windows en entornos con proxy interno, proxy con autenticación e inspección TLS —del tipo «funciona en la máquina de desarrollo pero no se puede comunicar en la red del cliente» o «al convertirlo en servicio dejó de conectar con la API externa»— así como sobre el diseño de la comunicación de aplicaciones empresariales pensado para un entorno con proxy (parámetros de configuración, timeouts, diseño de logs). Puede empezar simplemente por ordenar el procedimiento para reproducir el fenómeno y la forma de recoger los logs.
- Desarrollo de aplicaciones Windows
- Investigación de defectos y análisis de causas
- Consultoría técnica y revisión de diseño
- Contacto
Referencias
-
Microsoft Learn, WinINet vs. WinHTTP. Sobre el criterio de uso —usar WinINET salvo en procesos que necesiten servicios, suplantación o separación de sesiones— y la tabla comparativa de funciones: caché de credenciales, aviso de credenciales, soporte de servicios, suplantación, separación de sesiones, etc. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, netsh winhttp. Sobre la sintaxis de netsh winhttp show/set/import/reset, proxy-server y bypass-list de set proxy, import proxy source=ie, y la configuración detallada en formato JSON (Proxy, ProxyBypass, AutoconfigUrl, AutoDetect) de set advproxy. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, About WinHTTP. Sobre WinHTTP como pila HTTP diseñada para usos de servicio y del lado servidor, que admite ejecución con cuenta de servicio y suplantación, pero no comparte las cookies, la caché, las credenciales ni las Opciones de Internet del usuario del navegador. ↩ ↩2 ↩3
-
Microsoft Learn, Using a proxy with Delivery Optimization. Sobre que netsh winhttp set proxy es una configuración estática que no admite detección automática, URL de PAC ni autenticación de proxy; la configuración de proxy por dispositivo para contextos sin usuario con sesión iniciada (CSP NetworkProxy, directiva «Configurar el proxy por equipo»); y que las comunicaciones con anclaje de certificado fallan con la inspección TLS y requieren exclusión. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Microsoft Learn, WinHTTP AutoProxy Support. Sobre que los scripts PAC incluyen la función FindProxyForURL(url, host) y calculan una lista de proxies por cada petición; que un valor de retorno especial indica que puede usarse conexión directa; y que en la API de AutoProxy tradicional el proxy automático no se integra automáticamente en la pila HTTP, por lo que la app debe llamar a WinHttpGetProxyForUrl. ↩ ↩2 ↩3
-
Microsoft Learn, WinHttpGetProxyForUrl function. Sobre que, como implementación del protocolo WPAD, hay que invocarla por cada URL porque el archivo PAC puede devolver un proxy distinto según la URL; y sobre que admite tanto la especificación explícita de una URL de PAC como la detección automática desde la red. ↩ ↩2
-
Microsoft Learn, HttpClient.DefaultProxy Property. Sobre que en Windows se leen primero las variables de entorno HTTP_PROXY, HTTPS_PROXY, ALL_PROXY y NO_PROXY, y si no están definidas se lee la configuración de proxy del usuario; que en Linux, sin variables de entorno, se inicializa sin proxy; que NO_PROXY no admite comodines y usa la coincidencia de subdominio mediante el punto inicial; y que la URL del proxy puede incluir usuario y contraseña. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Microsoft Learn, Configuring Internet Applications. Sobre que en .NET Framework el elemento defaultProxy define el proxy predeterminado; que HttpWebRequest sin la propiedad Proxy usa el proxy predeterminado; y que la configuración de Internet del sistema se combina con la del archivo de configuración, teniendo prioridad esta última. ↩ ↩2 ↩3
-
Microsoft Learn, defaultProxy element (network settings). Sobre los atributos enabled y useDefaultCredentials del elemento system.net/defaultProxy, sus elementos hijos proxy, bypasslist y module; que si el elemento queda vacío se usa la configuración de proxy del sistema; y que, al migrar a .NET 6 en adelante, se configura mediante HttpClient.DefaultProxy. ↩ ↩2 ↩3
-
Microsoft Learn, Authentication in WinHTTP. Sobre que cuando se requiere autenticación de proxy se devuelve el código de estado 407 junto con la cabecera Proxy-Authenticate (la autenticación de servidor usa 401 y WWW-Authenticate); la diferencia entre la autenticación Basic y los métodos de desafío-respuesta como Kerberos; y que en los métodos de desafío-respuesta el nombre de usuario y la contraseña no circulan por la red. ↩ ↩2 ↩3
-
Microsoft Learn, HttpClientHandler.DefaultProxyCredentials Property. Sobre la propiedad que, cuando UseProxy es true y Proxy es null (se usa el proxy predeterminado del sistema), establece las credenciales usadas para la autenticación frente a ese proxy predeterminado. ↩ ↩2
-
Microsoft Learn, WebProxy.Credentials Property. Sobre que la propiedad Credentials son las credenciales que se envían al proxy en respuesta a un HTTP 407; y que en muchos escenarios de cliente se recomienda establecer UseDefaultCredentials en true para usar las credenciales predeterminadas del usuario con sesión iniciada. ↩ ↩2
-
Microsoft Learn, Understanding implications when using network intermediation to decrypt or manipulate Microsoft 365 traffic at the network layer. Sobre que la inspección TLS (descifrado SSL) es una configuración en la que un proxy o firewall descifra, inspecciona y vuelve a cifrar el TLS; que puede provocar fallos de funcionamiento o degradación del rendimiento en servicios que presuponen TLS de extremo a extremo; y sobre la recomendación de excluir el tráfico dirigido a Microsoft 365 del descifrado e inspección en la capa de red. ↩ ↩2 ↩3
-
Microsoft Learn, Make HTTP requests with the HttpClient class. Sobre las dos formas de configuración —HttpClient.DefaultProxy y HttpClientHandler.Proxy—; que especificar Proxy tiene prioridad sobre el archivo de configuración y sobre la configuración del equipo local; la configuración habitual en la que WPAD obtiene el archivo PAC (wpad.dat, etc.) mediante el nombre wpad de DNS o mediante DHCP; y la lógica de exclusión de destinos locales por nombre plano, loopback o coincidencia de sufijo de dominio. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, WinHttpOpen function. Sobre el significado de cada valor de dwAccessType: WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY (Windows 8.1 en adelante) usa la configuración de proxy del sistema o del usuario para determinar el proxy automáticamente, gestionando también el failover y la autenticación; WINHTTP_ACCESS_TYPE_DEFAULT_PROXY queda obsoleto desde 8.1. ↩
-
Microsoft Learn, Work with existing on-premises proxy servers. Sobre que la comunicación HTTPS saliente se establece mediante una petición CONNECT al proxy; que si tiene éxito se devuelve HTTP 200; y que respuestas como 407 (solicitud de autenticación) o 502 indican que el proxy no ha permitido la comunicación, por lo que conviene avanzar el diagnóstico junto con el equipo responsable del proxy. ↩
Artículos relacionados
Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.
No envuelvas HttpClient en un using ── Comunicación HTTP en aplicaciones de negocio C# (patrones de creación, tiempos de espera y reintentos)
Crear HttpClient con using en cada solicitud agota los sockets, y usarlo como static no sigue los cambios de DNS. Repasamos el patrón de ...
Captura de paquetes en Windows en la práctica — pktmon, netsh trace y Wireshark: cuándo usar cada uno
Los fallos que solo dejan «tiempo de espera» en el log se investigan mejor viendo los paquetes reales, capturables con pktmon y netsh tra...
Buenas prácticas de multithreading en la práctica — Edición .NET: qué decidir antes de aumentar los hilos
Reglas de diseño en .NET/C# para evitar fallos y bloqueos intermitentes con hilos: usar Task en lugar de hilos propios, reducir el estado...
Usar WMI/CIM desde C# y PowerShell ── Guía práctica de obtención de información de hardware, monitorización de procesos y consultas remotas
WMI/CIM es la solución estándar para leer el número de serie, monitorizar el disco y detectar procesos. Cmdlets CIM, migración desde Get-...
Las profundidades de la E/S de Windows (parte 5) — Estructura interna de NTFS: comprender el sistema de archivos a partir de la MFT
Quinta entrega sobre la estructura interna de NTFS: la MFT, los flujos de datos, los enlaces físicos, los puntos de análisis y los dos di...
Temas relacionados
Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.
Temas técnicos de Windows
Portal sobre desarrollo de Windows, investigación de fallos y aprovechamiento de activos existentes.
Servicios relacionados con este tema
El artículo está directamente relacionado con los siguientes servicios.
Desarrollo de aplicaciones para Windows
Aplicaciones empresariales, integración de dispositivos y herramientas de comunicación, de los requisitos al desarrollo.
Preguntas frecuentes
Preguntas habituales en las consultas sobre el tema del artículo.
- El navegador conecta, pero solo la aplicación empresarial no puede atravesar el proxy interno. ¿Por qué?
- El navegador lee la configuración de proxy por usuario de WinINET, pero no todas las aplicaciones empresariales leen la misma configuración. Una app que se ejecuta como servicio de Windows o con otra cuenta consulta la configuración visible desde esa cuenta, la configuración de máquina de WinHTTP o las variables de entorno. Primero identifique la cuenta con la que se ejecuta y compruebe la configuración de proxy visible desde esa cuenta tanto con netsh winhttp show proxy como en la configuración de usuario. Si puede reproducir el problema con curl.exe u otra herramienta usando la misma cuenta y la misma máquina, se trata de una discrepancia entre sistemas de configuración y no de un problema propio de la aplicación.
- Configuré netsh winhttp set proxy, pero la comunicación de la aplicación no cambia. ¿Por qué?
- netsh winhttp configura el valor predeterminado de máquina de WinHTTP, y no afecta a los navegadores ni a las aplicaciones interactivas que leen WinINET, ni al HttpClient de .NET (Core en adelante), que prioriza las variables de entorno. Además, netsh winhttp set proxy es una configuración estática que no gestiona la configuración automática mediante PAC, la detección automática ni la autenticación de proxy. Primero hay que confirmar con qué pila HTTP trabaja la aplicación en cuestión y de qué sistema de configuración resuelve el proxy.
- ¿Qué configuración de proxy leen las aplicaciones .NET?
- .NET Framework usa por defecto la configuración de Opciones de Internet (equivalente a WinINET) de la cuenta en ejecución, y puede sobrescribirse con el elemento system.net/defaultProxy de app.config. El HttpClient de .NET (Core en adelante) lee primero variables de entorno como HTTP_PROXY, HTTPS_PROXY y NO_PROXY, y si no están definidas recurre a la configuración de proxy de usuario de Windows. En ambos casos, si se especifica explícitamente con HttpClientHandler.Proxy, esa especificación tiene prioridad máxima. Es decir, el orden de resolución predeterminado difiere entre Framework y Core en adelante, por lo que al migrar conviene revisar de nuevo el comportamiento del proxy.
- ¿Qué se debe comprobar cuando aparece 407 Proxy Authentication Required?
- El 407 es una señal de que el propio proxy exige autenticación, algo distinto de un error de autenticación del servidor de destino (401). Primero confirme, mediante la cabecera Proxy-Authenticate, qué método de autenticación exige el proxy (Negotiate, NTLM, Basic), y en .NET pase las credenciales con HttpClientHandler.DefaultProxyCredentials o WebProxy.UseDefaultCredentials. En aplicaciones que se ejecutan con una cuenta de servicio, las «credenciales predeterminadas» pasan a ser las de esa cuenta de servicio, por lo que es típico que algo funcione con un usuario interactivo pero devuelva 407 en cuanto se convierte en servicio. Compruebe también, en los registros del propio proxy, con qué identidad se autenticó.
- Con un proxy de inspección TLS obtengo errores de certificado. ¿Puedo desactivar la validación de certificados?
- No se recomienda desactivarla. Un proxy de inspección TLS descifra la comunicación y presenta al cliente un certificado re-firmado por su propia CA, de modo que si esa CA no está en las entidades de confianza, se produce un error de validación. La solución correcta es distribuir el certificado de la CA interna al almacén de certificados de Windows (normalmente Entidades de certificación raíz de confianza del equipo local). Desactivar la validación en el código impide detectar ataques de intermediario cuando la aplicación se usa fuera de la red corporativa, y deja una vulnerabilidad permanente.
Perfil del autor
Página de presentación del autor del artículo.
Go Komura
Representante de KomuraSoft LLC
Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.