net consumir asp c# ssl asp.net-web-api https client-certificates

c# - consumir - login api asp net



Deshabilitar el certificado de cliente SSL en*algunos*controladores WebAPI? (3)

Desafortunadamente, esto no se puede configurar en el nivel del controlador. El servidor decide qué controlador usar en función del contenido de una solicitud HTTP (generalmente la ruta de solicitud). SSL protege el contenido de un mensaje HTTP al cifrarlo, y la ruta de solicitud forma parte del mensaje cifrado. El canal SSL debe configurarse antes de enviar los mensajes HTTP, por lo que la configuración del canal SSL (ya sea que el servidor intente negociar un certificado de cliente, por ejemplo) no puede confiar en el contenido de ningún HTTP mensajes

Así que aquí están tus opciones:

  1. Haga girar una segunda función web que está configurada para no negociar certificados de clientes. Necesitará un segundo dominio para esto, ya que es esencialmente un servicio separado. Por lo tanto, tendría https://domain.com apuntando al certificado que no es de cliente y https://foo.domain.com apuntando al que sí requiere certificados de cliente.

  2. Use el mismo rol web, pero configure un segundo puerto para que IIS lo escuche y configúrelo para que no negocie un certificado de cliente. Sin embargo, usar puertos no estándar es una molestia, ya que uno de sus clientes tendrá que hacer https://domain.com:444 (o algún otro puerto además de 443).

  3. Deshabilitar la negociación de certificados de clientes en todos los ámbitos. Es posible que esto no funcione dependiendo de cómo su servicio acceda al certificado del cliente, pero normalmente cuando accede a la propiedad ClientCertificate en un objeto System.Web.HttpRequest (o equivalente), negociará un certificado a pedido. Esto significa que derriba de manera transparente la sesión SSL existente y establece una nueva, esta vez desafiando al cliente por el certificado. Esto es bastante ineficiente, ya que la configuración de una conexión SSL en primer lugar toma varios viajes de ida y vuelta, y hacerlo dos veces es doloroso. Pero dependiendo de sus opciones disponibles, los requisitos de rendimiento para las solicitudes que utilizan certificados de clientes y si obtendrá una gran cantidad de reutilización de la conexión de keep-alives, esta opción puede tener sentido.

Espero que esto ayude.

Editar para futuros lectores : Desafortunadamente, la recompensa otorgada no funciona; nada que pueda hacer al respecto ahora. Pero lea mi propia respuesta a continuación (a través de pruebas): se confirmó que funciona con cambios mínimos de código

Tenemos un servicio en la nube de Azure (WebRole) que está completamente en ASP.NET WebAPI 2.2 (sin MVC, el extremo frontal es angular). Algunos de nuestros controladores / puntos finales REST se comunican con un servicio en la nube de terceros a través de SSL (cliente cert auth / mutual auth) y el resto de los controladores / puntos finales se comunican con HTML5 / AngularJS front end, también a través de SSL (pero el servidor es más tradicional. SSL). No tenemos ningún punto final no SSL. Hemos habilitado Client SSL a través de una tarea de inicio de servicio en la nube como:

IF NOT DEFINED APPCMD SET APPCMD=%SystemRoot%/system32/inetsrv/AppCmd.exe %APPCMD% unlock config /section:system.webServer/security/access

Problema: la configuración está en todo el sitio, por lo que incluso cuando los usuarios llegan a la primera página (por ejemplo, https://domain.com , devuelve el index.html para angularJS), su navegador les pide el certificado SSL del cliente. (imagen abajo)

Si hay una manera de cualquiera

  1. ¿Limitar las solicitudes de certificado SSL del cliente solo a los controladores WebAPI que hablan con el servicio de nube de terceros?

O

  1. ¿Desea omitir la autenticación SSL del cliente para nuestros controladores webapi de front-end?

El archivo web.config de nuestro servidor es complejo, pero el fragmento de código relevante se encuentra a continuación:

<system.webServer> <security> <access sslFlags="SslNegotiateCert" /> </security> </system.webServer>

Y la captura de pantalla del cliente que llega a un punto final de WebAPI regular pero intenta la autenticación SSL del cliente (ocurre en cualquier navegador, Chrome, Firefox o IE)


Desafortunadamente, la respuesta de Cleftheris a la que se le otorgó la recompensa no funciona. Intenta trabajar demasiado tarde en el procesamiento / canalización del servidor HTTP para obtener el certificado del cliente, pero esta publicación me dio algunas ideas.

La solución se basa en web.config que requiere un manejo especial de "directorios" (también funciona para carpetas virtuales o rutas WebAPI).

Aquí está la lógica deseada:

https://www.server.com/acmeapi/ ** => SSL con certificados de cliente

https://www.server.com/ ** => SSL

Aquí está la configuración correspondiente.

<configuration> ... <system.webServer> <!-- This is for the rest of the site --> <security> <access sslFlags="Ssl" /> </security> </system.webServer> <!--This is for the 3rd party API endpoint--> <location path="acmeapi"> <system.webServer> <security> <access sslFlags="SslNegotiateCert"/> </security> </system.webServer> </location> ... </configuration>

Puntos extra

Lo anterior configurará el protocolo de enlace SSL en consecuencia. Ahora aún debe verificar el certificado SSL del cliente en su código si es el que espera. Eso se hace de la siguiente manera

Código del controlador:

[RoutePrefix("acmeapi")] [SslClientCertActionFilter] // <== key part! public class AcmeProviderController : ApiController { [HttpGet] [Route("{userId}")] public async Task<OutputDto> GetInfo(Guid userId) { // do work ... } }

El atributo real de arriba que realiza la validación del Cliente SSL está abajo. Se puede utilizar para decorar todo el controlador o solo métodos específicos.

public class SslClientCertActionFilterAttribute : ActionFilterAttribute { public List<string> AllowedThumbprints = new List<string>() { // Replace with the thumbprints the 3rd party // server will be presenting. You can make checks // more elaborate but always have thumbprint checking ... "0011223344556677889900112233445566778899", "1122334455667788990011223344556677889900" }; public override void OnActionExecuting(HttpActionContext actionContext) { var request = actionContext.Request; if (!AuthorizeRequest(request)) { throw new HttpResponseException(HttpStatusCode.Forbidden); } } private bool AuthorizeRequest(HttpRequestMessage request) { if (request==null) throw new ArgumentNullException("request"); var clientCertificate = request.GetClientCertificate(); if (clientCertificate == null || AllowedThumbprints == null || AllowedThumbprints.Count < 1) { return false; } foreach (var thumbprint in AllowedThumbprints) { if (clientCertificate.Thumbprint != null && clientCertificate.Thumbprint.Equals(thumbprint, StringComparison.InvariantCultureIgnoreCase)) { return true; } } return false; } }


Simplemente podría permitir el tráfico http simple en el nivel web.config y escribir un controlador de delegación personalizado en la canalización de Web Api para esto. Puede encontrar un controlador de delegado de certificados de cliente here y here . Luego, podría hacer que este manejador se active "Por ruta" como se encuentra en este ejemplo here :

Esto es lo que su configuración de ruta se vería.

public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "Route1", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Routes.MapHttpRoute( name: "Route2", routeTemplate: "api2/{controller}/{id}", defaults: new { id = RouteParameter.Optional }, constraints: null, handler: new CustomCertificateMessageHandler() // per-route message handler ); config.MessageHandlers.Add(new SomeOtherMessageHandler()); // global message handler } }

Tenga en cuenta que, en caso de que necesite controladores de delegación "por ruta", no debe incluirlos en la lista global de controladores de mensajes.