¿Cómo desactivo la recuperación de SSL y uso solo TLS para conexiones salientes en .NET? (Mitigación del caniche)

Estoy tratando de mitigar nuestra vulnerabilidad al ataque de Poodle SSL 3.0 Fallback . Nuestros administradores ya han comenzado a deshabilitar SSL a favor de TLS para las conexiones entrantes a nuestros servidores. Y también hemos aconsejado a nuestro equipo que deshabilite SSL en sus navegadores web. Ahora estoy mirando nuestra base de código .NET, que inicia conexiones HTTPS con varios servicios a través de System.Net.HttpWebRequest . Creo que estas conexiones podrían ser vulnerables a un ataque MITM si permiten el repliegue de TLS a SSL. Esto es lo que he determinado hasta ahora. ¿Podría alguien comprobarlo para verificar que estoy en lo correcto? Esta vulnerabilidad es nueva, por lo que aún no he visto ninguna orientación de Microsoft sobre cómo mitigarla en .NET:

  1. Los protocolos permitidos para la clase System.Net.Security.SslStream, que sustenta la comunicación segura en .NET, se establecen globalmente para cada dominio de aplicación a través de la propiedad System.Net.ServicePointManager.SecurityProtocol .

  2. El valor predeterminado de esta propiedad en .NET 4.5 es Ssl3 | Tls Ssl3 | Tls (aunque no puedo encontrar documentación que lo respalde). SecurityProtocolType es una enumeración con el atributo Flags, por lo que es un OR bit a bit de esos dos valores. Puede verificar esto en su entorno con esta línea de código:

    Console.WriteLine (System.Net.ServicePointManager.SecurityProtocol.ToString ());

  3. Esto se debe cambiar a solo Tls , o quizás a Tls12 , antes de iniciar cualquier conexión en su aplicación:

    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls;

  4. Importante: Dado que la propiedad es compatible con varios indicadores bit a bit, supongo que el SslStream no retrocederá automáticamente a otros protocolos no especificados durante el protocolo de enlace. De lo contrario, ¿cuál sería el punto de apoyar múltiples banderas?

Actualización en TLS 1.0 contra 1.1 / 1.2:

Según el experto en seguridad de Google, Adam Langley, posteriormente se descubrió que TLS 1.0 era vulnerable a POODLE si no se implementaba correctamente , por lo que debería considerar cambiarse a TLS 1.2 exclusivamente.

Estamos haciendo lo mismo. Para admitir solo TLS 1.2 y sin protocolos SSL, puede hacer esto:

 System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 

SecurityProtocolType.Tls es solo TLS 1.0, no todas las versiones de TLS.

Como un lado: si desea comprobar que su sitio no permite conexiones SSL, puede hacerlo aquí (no creo que esto se vea afectado por la configuración anterior, tuvimos que editar el registro para obligar a IIS a usar TLS para las conexiones entrantes): https://www.ssllabs.com/ssltest/index.html

Para deshabilitar SSL 2.0 y 3.0 en IIS, consulte esta página: https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html

La respuesta de @Eddie Loeffen parece ser la respuesta más popular a esta pregunta, pero tiene algunos malos efectos a largo plazo. Si revisa la página de documentación para System.Net.ServicePointManager.SecurityProtocol aquí, la sección de comentarios implica que la fase de negociación debe abordar esto (y forzar el protocolo es una mala práctica porque en el futuro, TLS 1.2 también se verá comprometida). Sin embargo, no estaríamos buscando esta respuesta si lo hiciera.

Investigando, parece que se necesita el protocolo de negociación ALPN para llegar a TLS1.2 en la fase de negociación. Tomamos eso como nuestro punto de partida y probamos versiones más nuevas del .Net Framework para ver dónde comienza el soporte. Descubrimos que .Net 4.5.2 no admite la negociación de TLS 1.2, pero .Net 4.6 sí.

Por lo tanto, aunque forzar TLS1.2 hará el trabajo ahora, le recomiendo que actualice a .Net 4.6 en su lugar. Como este es un problema de PCI DSS para junio de 2016, la ventana es corta, pero el nuevo marco es una mejor respuesta.

ACTUALIZACIÓN: trabajando a partir de los comentarios, construí esto:

 ServicePointManager.SecurityProtocol = 0; foreach (SecurityProtocolType protocol in SecurityProtocolType.GetValues(typeof(SecurityProtocolType))) { switch (protocol) { case SecurityProtocolType.Ssl3: case SecurityProtocolType.Tls: case SecurityProtocolType.Tls11: break; default: ServicePointManager.SecurityProtocol |= protocol; break; } } 

Para validar el concepto, armé SSL3 y TLS1.2 y ejecuté el código dirigido a un servidor que solo admite TLS 1.0 y TLS 1.2 (1.1 está deshabilitado). Con los protocolos ordenados, parece conectarse bien. Si cambio a SSL3 y TLS 1.1, no se pudo conectar. Mi validación utiliza HttpWebRequest desde System.Net y simplemente llama a GetResponse (). Por ejemplo, intenté esto y fallé:

  HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest; ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls11; request.GetResponse(); 

mientras esto funcionó:

  HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest; ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12; request.GetResponse(); 

Esto tiene una ventaja sobre forzar TLS 1.2 en eso, si el marco .Net se mejora de modo que haya más entradas en el Enum, serán apoyadas por el código como está. Tiene una desventaja sobre el solo uso de .Net 4.6 porque 4.6 usa ALPN y debería admitir nuevos protocolos si no se especifica ninguna restricción.

@watson

En formularios de Windows está disponible, en la parte superior de la clase poner

  static void Main(string[] args) { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; //other stuff here } 

dado que Windows tiene un solo subproceso, es todo lo que necesita, en el caso de que sea un servicio, debe colocarlo justo encima de la llamada al servicio (ya que no se sabe en qué subproceso estará).

 using System.Security.Principal 

también es necesario.

Tuve que convertir el entero equivalente para evitar el hecho de que todavía estoy usando .NET 4.0

 System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; /* Note the property type [System.Flags] public enum SecurityProtocolType { Ssl3 = 48, Tls = 192, Tls11 = 768, Tls12 = 3072, } */ 

Si tiene curiosidad acerca de qué protocolos admite .NET, puede probar HttpClient en https://www.howsmyssl.com/

 // set proxy if you need to // WebRequest.DefaultWebProxy = new WebProxy("http://localhost:3128"); File.WriteAllText("howsmyssl-httpclient.html", new HttpClient().GetStringAsync("https://www.howsmyssl.com").Result); // alternative using WebClient for older framework versions // new WebClient().DownloadFile("https://www.howsmyssl.com/", "howsmyssl-webclient.html"); 

El resultado es condenatorio:

Su cliente está usando TLS 1.0, que es muy antiguo, posiblemente susceptible al ataque BEAST, y no tiene las mejores suites de cifrado disponibles en él. Las adiciones como AES-GCM y SHA256 para reemplazar MD5-SHA-1 no están disponibles para un cliente de TLS 1.0, así como para muchas más suites de cifrado modernas.

Como explica Eddie arriba, puedes habilitar mejores protocolos manualmente:

 System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; 

No sé por qué usa malos protocolos de fábrica. Esa parece una opción de configuración deficiente, equivalente a un error de seguridad importante (apuesto a que muchas aplicaciones no cambian el valor predeterminado). ¿Cómo podemos informarlo?

Encontré que la solución más simple es agregar dos entradas de registro de la siguiente manera (ejecutar esto en un símbolo del sistema con privilegios de administrador):

 reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:32 reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:64 

Estas entradas parecen afectar la forma en que .NET CLR elige un protocolo cuando realiza una conexión segura como cliente.

Hay más información sobre esta entrada de registro aquí:

https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2015/2960358#suggested-actions

Esto no solo es más simple, sino que supone que funciona para su caso, mucho más sólido que una solución basada en código, que requiere que los desarrolladores rastreen el protocolo y el desarrollo y actualicen todos sus códigos relevantes. Afortunadamente, se pueden hacer cambios de entorno similares para TLS 1.3 y posteriores, siempre que .NET siga siendo lo suficientemente tonto como para no elegir automáticamente el protocolo más alto disponible.

NOTA : aunque, de acuerdo con el artículo anterior, esto solo debe deshabilitar RC4, y uno no pensaría que esto cambiaría si el cliente .NET puede usar TLS1.2 + o no, por alguna razón tiene este efecto.

NOTA : Como señaló @Jordan Rieger en los comentarios, esta no es una solución para POODLE, ya que no deshabilita los protocolos anteriores, simplemente permite que el cliente trabaje con protocolos más nuevos, por ejemplo, cuando un servidor parcheado ha desactivado el antiguo. protocolos. Sin embargo, con un ataque MITM, obviamente un servidor comprometido ofrecerá al cliente un protocolo anterior, que el cliente utilizará felizmente.

TODO : intente deshabilitar el uso del lado del cliente de TLS1.0 y TLS1.1 con estas entradas de registro, sin embargo, no sé si las bibliotecas .NET http client respetan estas configuraciones o no:

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-10

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-11