SSL Certificate Based Authentication In Web API Project

Table of Contents

  • Introduction
  • Objectives
  • SSL Client Certificates
  • How to Install SSL Certificate
  • SSL Authentication Code
  • IP Whitelisting
  • References

Introduction

This document describes the purpose, features and implementation of SSL Certificate based authentication in Web API projects.

Objectives

Web API assumes that authentication happens in the host. For web-hosting, the host is IIS, which uses HTTP modules for authentication. You can configure your project to use any of the authentication modules built in to IIS or ASP.NET, or write your own HTTP module to perform custom authentication.

Several common authentication schemes are not secure over plain HTTP. In particular, Basic authentication and forms authentication send unencrypted credentials. To be secure, these authentication schemes must use SSL. In addition, SSL client certificates can be used to authenticate clients.

SSL Client Certificates

SSL provides authentication by using Public Key Infrastructure certificates. The server must provide a certificate that authenticates the server to the client. It is less common for the client to provide a certificate to the server, but this is one option for authenticating clients. To use client certificates with SSL, you need a way to distribute signed certificates to your users. For many application types, this will not be a good user experience, but in some environments (for example, enterprise) it may be feasible.

Advantages

  1. Certificate credentials are stronger than username/password.
  2. SSL provides a complete secure channel, with authentication, message integrity, and message encryption.

Disadvantages

  1. You must obtain and manage PKI certificates.
  2. The client platform must support SSL client certificates.

To configure IIS to accept client certificates, open IIS Manager and perform the following steps:

  1. Click the site node in the tree view.
  2. Double-click the SSL Settings feature in the middle pane.
  3. Under Client Certificates, select one of these options:

      Accept: IIS will accept a certificate from the client, but does not require one.

      Require: Require a client certificate. (To enable this option, you must also select "Require SSL")

Using Client Certificates in Web API

On the server side, you can get the client certificate by calling GetClientCertificate() on the request message. The method returns null if there is no client certificate. Otherwise, it returns an X509Certificate2 instance. Use this object to get information from the certificate, such as the issuer and subject. Then you can use this information for authentication and/or authorization.

How to Install SSL Certificate

There are total two certificates that you need to install and configure on your development machine,

  1. Install the Certificate.cer certificate in your Trusted Root Certification Authorities for the Local Machine store using MMC (right-click over the Trusted Root Certification Authorities folder | All Tasks | Import).

    Example screenshot:

    Certificate.cer

  2. Install the ClientCert.pfx certificate in the Personal store of Local Computer using MMC. Notice that the certificate shows it was issued by your Certificate Authority.

    Certificate Authority

We already installed certificates on PY server. Following procedure shows how to install required certificates on server.

  1. Install above 2 certificates on server.

  2. Install the PvtSSLCert.pfx certificate in the Personal store of Local Computer using MMC. Notice that the certificate shows it was issued byyour Certificate Authority.

    Local host

SSL Authentication Code

  1. using System;  
  2. using System.Security.Claims;  
  3. using System.Security.Cryptography.X509Certificates;  
  4. using System.Threading.Tasks;  
  5. using Microsoft.Owin;  
  6. namespaceProject.Owin.Middleware  
  7. {  
  8.     ///<summary>  
  9.     /// CertificateAuthenticationMiddleware class is used to secure the web API using certificate based   
  10.     /// Authentication. This class inherits OwinMiddlerware class.  
  11.     ///</summary>  
  12.   
  13.     publicclassCertificateAuthenticationMiddleware: OwinMiddleware  
  14.     {  
  15.         conststring OwinCertFunc = "ssl.LoadClientCertAsync";  
  16.         conststring OwinCert = "ssl.ClientCertificate";  
  17.         conststring OwinCertError = "ssl.ClientCertificateErrors";  
  18.         public CertificateAuthenticationMiddleware(OwinMiddleware next): base(next)  
  19.         {}  
  20.   
  21.             ///<summary>  
  22.             /// The Invoke() method is invocked from startup class of OWIN for security.  
  23.             ///</summary>  
  24.             ///<param name="context"></param>  
  25.             ///<returns></returns>  
  26.   
  27.         publicasyncoverrideTask Invoke(IOwinContext context)  
  28.         {  
  29.             if (context.Environment.Keys.Contains(OwinCertFunc))  
  30.             {  
  31.                 try  
  32.                 {  
  33.                     var task = (context.Environment[OwinCertFunc] asFunc < Task > );  
  34.                     awaitTask.Run(task);  
  35.                     if (context.Environment.Keys.Contains(OwinCert))  
  36.                     {  
  37.                         var cert = context.Environment[OwinCert] asX509Certificate;  
  38.                         if (cert != null) context.Request.Environment.Add(SystemContants.OwinMannatechClientInfo, cert.Subject);  
  39.                         else  
  40.                         {  
  41.                             context.Response.StatusCode = 403;  
  42.                             return;  
  43.                         }  
  44.                     }  
  45.                     else  
  46.                     {  
  47.                         context.Response.StatusCode = 403;  
  48.                         return;  
  49.                     }  
  50.                     // Exception certError;  
  51.                     if (context.Environment.Keys.Contains(OwinCertError))  
  52.                     {  
  53.                         //certError = context.Environment[OwinCertError] as Exception;  
  54.                         context.Response.StatusCode = 403;  
  55.                         return;  
  56.                     }  
  57.                 }  
  58.                 catch (Exception ex)  
  59.                 {  
  60.                     context.Response.StatusCode = 403;  
  61.                     return;  
  62.                 }  
  63.             }  
  64.             else  
  65.             {  
  66.                 context.Response.StatusCode = 403;  
  67.                 return;  
  68.             }  
  69.             await Next.Invoke(context);  
  70.         }  
  71.     }  
  72. }  
IP WhiteListing

Using the OWIN middleware here we can whitelist the range of IP Addresses or the specific IP address. If the request comes only from these whitelisted IP addresses then the API respond to that request.

Below is the code of IP whitelisting.
  1. using System.Collections.Generic;  
  2. using System.Threading.Tasks;  
  3. using Microsoft.Owin;  
  4. namespaceProject.Owin.Middleware  
  5. {  
  6.     ///<summary>  
  7.     /// IpWhiteListMiddleware class is used to secure the web API, It gives the acess only those IP addesss   
  8.     /// which are configured in "Web.config". This class inherits OwinMiddlerware class.  
  9.     ///</summary>  
  10.   
  11.     publicclassIpWhiteListMiddleware: OwinMiddleware  
  12.     {  
  13.         privatereadonlyHashSet < string > _whitelistIps;  
  14.         public IpWhiteListMiddleware(OwinMiddleware next, HashSet < string > whitelistIps): base(next)  
  15.             {  
  16.                 _whitelistIps = whitelistIps;  
  17.             }  
  18.   
  19.             ///<summary>  
  20.             /// The Invoke() method is invocked from startup class of OWIN for security.  
  21.             ///</summary>  
  22.             ///<param name="context"></param>  
  23.             ///<returns></returns>  
  24.   
  25.         publicasyncoverrideTask Invoke(IOwinContext context)  
  26.         {  
  27.             if (!_whitelistIps.Contains(context.Request.RemoteIpAddress) && !context.Request.IsLocal())  
  28.             {  
  29.                 //context.Response.StatusCode = 404;  
  30.   
  31.                 var response = context.Response;  
  32.                 var request = context.Request;  
  33.                 response.OnSendingHeaders(state =>  
  34.                 {  
  35.                     var resp = (OwinResponse) state;  
  36.                     resp.StatusCode = 200;  
  37.                     resp.ReasonPhrase = "IP address is not registered"// if you're going to change the status code  
  38.                     // you probably should also change the reason phrase  
  39.   
  40.                 }, response);  
  41.                 return;  
  42.             }  
  43.             await Next.Invoke(context);  
  44.         }  
  45.     }  
  46. }  
Startup.cs
  1. publicclassStartup  
  2. {  
  3.     ///<summary>  
  4.     /// Owin Configuration method for IP Whitelisting and the Certificate based authentication  
  5.     ///</summary>  
  6.   
  7.     publicvoid Configuration(IAppBuilder app)  
  8.     {  
  9.         app.UseHttpTracking(newHttpTrackingOptions  
  10.         {  
  11.             TrackingStore = newHttpTrackingStore(),  
  12.                 TrackingIdPropertyName = "x-tracking-id",  
  13.                 MaximumRecordedRequestLength = 64 * 1024,  
  14.                 MaximumRecordedResponseLength = 64 * 1024,  
  15.         });  
  16.   
  17.         string[] IPList = ConfigurationManager.AppSettings["IPWhiteList"].Split(',').Select(s => s.ToString()).ToArray();  
  18.         var whitelistIps = newHashSet < string > (IPList);  
  19.   
  20.         //var whitelistIps = new HashSet<string> { "14.140.150.214", "50.200.185.198", "67.208.128.168","10.77.5.52" };  
  21.   
  22.         app.Use(typeof(IpWhiteListMiddleware), whitelistIps);  
  23.         app.Use(typeof(CertificateAuthenticationMiddleware));  
  24.         var config = newHttpConfiguration();  
  25.         WebApiConfig.Register(config);  
  26.         app.UseWebApi(config);  
  27.         config.Services.Clear(typeof(ModelValidatorProvider));  
  28.         log4net.Config.XmlConfigurator.Configure();  
  29.     }  
  30. }  
References

 

Read more articles on Security in .NET:

Up Next
    Ebook Download
    View all
    Learn
    View all