Come configurare l'autenticazione reciproca TLS per un'app WebHow To Configure TLS Mutual Authentication for Web App

PanoramicaOverview

È possibile limitare l'accesso all'app web di Azure abilitandone diversi tipi di autenticazione.You can restrict access to your Azure web app by enabling different types of authentication for it. A questo scopo è possibile eseguire l'autenticazione usando un certificato client quando la richiesta è per TLS/SSL.One way to do so is to authenticate using a client certificate when the request is over TLS/SSL. Questo meccanismo è detto l'autenticazione reciproca TLS o autenticazione del certificato client. Questo articolo illustra come configurare un'app Web per l'uso dell'autenticazione del certificato client.This mechanism is called TLS mutual authentication or client certificate authentication and this article will detail how to set up your web app to use client certificate authentication.

Nota: se si accede al sito tramite HTTP e non HTTPS, non si riceveranno i certificati client.Note: If you access your site over HTTP and not HTTPS, you will not receive any client certificate. Pertanto, se l'applicazione richiede i certificati client è consigliabile non consentire le richieste all'applicazione tramite HTTP.So if your application requires client certificates you should not allow requests to your application over HTTP.

Nota

Sebbene in questo articolo si faccia riferimento alle app Web, è applicabile anche ad app per le API e app per dispositivi mobili.Although this article refers to web apps, it also applies to API apps and mobile apps.

Configurare l'app Web per l'autenticazione del certificato clientConfigure Web App for Client Certificate Authentication

Per configurare l'app Web per richiedere certificati client, è necessario aggiungere l'impostazione del sito clientCertEnabled per l'app Web e impostarla su true.To set up your web app to require client certificates, you need to add the clientCertEnabled site setting for your web app and set it to true. Questa impostazione può anche essere configurata nel portale di Azure nel pannello dei certificati SSL.This setting is also able to be configured in the Azure portal under the SSL certificates blade.

Per semplificare la definizione della chiamata all'API REST, è possibile usare lo strumento ARMClient .You can use the ARMClient tool to make it easy to craft the REST API call. Dopo l'accesso con lo strumento, sarà necessario eseguire il comando seguente:After you sign in with the tool, you will need to issue the following command:

ARMClient PUT subscriptions/{Subscription Id}/resourcegroups/{Resource Group Name}/providers/Microsoft.Web/sites/{Website Name}?api-version=2015-04-01 @enableclientcert.json -verbose

sostituire tutti gli elementi tra {} con le informazioni per l'app Web e la creare un file denominato enableclientcert.json con il contenuto JSON seguente:replacing everything in {} with information for your web app and creating a file called enableclientcert.json with the following JSON content:

{
    "location": "My Web App Location",
    "properties": {
        "clientCertEnabled": true
    }
}

Assicurarsi di modificare il valore di "posizione" con la posizione in cui si trova l'app Web, ad esempio Stati Uniti centro-settentrionali o Stati Uniti occidentali e così via.Make sure to change the value of "location" to wherever your web app is located for example, North Central US or West US etc.

È anche possibile usare https://resources.azure.com per capovolgere la proprietà clientCertEnabled tramite in true.You can also use https://resources.azure.com to flip the clientCertEnabled property to true.

Nota: se si esegue ARMClient da Powershell, è necessario eseguire l'escape del simbolo @ per il file JSON con un apice inverso `.Note: If you run ARMClient from Powershell, you will need to escape the @ symbol for the JSON file with a back tick `.

Accesso al certificato client dall'app WebAccessing the Client Certificate From Your Web App

Se si usa ASP.NET e si configura l'applicazione per l'uso dell'autenticazione del certificato client, il certificato sarà disponibile tramite la proprietà HttpRequest.ClientCertificate .If you are using ASP.NET and configure your app to use client certificate authentication, the certificate will be available through the HttpRequest.ClientCertificate property. Per gli altri stack di applicazioni, il certificato client è disponibile nell'app tramite un valore con codifica Base64 nell'intestazione della richiesta "X-ARR ClientCert".For other application stacks, the client cert will be available in your app through a base64 encoded value in the "X-ARR-ClientCert" request header. L'applicazione può creare un certificato da questo valore e quindi usarlo a scopo di autenticazione e autorizzazione nell'applicazione.Your application can create a certificate from this value and then use it for authentication and authorization purposes in your application.

Considerazioni speciali per la convalida del certificatoSpecial Considerations for Certificate Validation

Il certificato client inviato all'applicazione non viene sottoposto ad alcuna convalida da parte della piattaforma di app Web di Azure.The client certificate that is sent to the application does not go through any validation by the Azure Web Apps platform. La convalida il certificato è responsabilità dell'app Web.Validating this certificate is the responsibility of the web app. Ecco un esempio di codice ASP.NET che convalida le proprietà del certificato a scopo di autenticazione.Here is sample ASP.NET code that validates certificate properties for authentication purposes.

using System;
using System.Collections.Specialized;
using System.Security.Cryptography.X509Certificates;
using System.Web;

namespace ClientCertificateUsageSample
{
    public partial class cert : System.Web.UI.Page
    {
        public string certHeader = "";
        public string errorString = "";
        private X509Certificate2 certificate = null;
        public string certThumbprint = "";
        public string certSubject = "";
        public string certIssuer = "";
        public string certSignatureAlg = "";
        public string certIssueDate = "";
        public string certExpiryDate = "";
        public bool isValidCert = false;

        //
        // Read the certificate from the header into an X509Certificate2 object
        // Display properties of the certificate on the page
        //
        protected void Page_Load(object sender, EventArgs e)
        {
            NameValueCollection headers = base.Request.Headers;
            certHeader = headers["X-ARR-ClientCert"];
            if (!String.IsNullOrEmpty(certHeader))
            {
                try
                {
                    byte[] clientCertBytes = Convert.FromBase64String(certHeader);
                    certificate = new X509Certificate2(clientCertBytes);
                    certSubject = certificate.Subject;
                    certIssuer = certificate.Issuer;
                    certThumbprint = certificate.Thumbprint;
                    certSignatureAlg = certificate.SignatureAlgorithm.FriendlyName;
                    certIssueDate = certificate.NotBefore.ToShortDateString() + " " + certificate.NotBefore.ToShortTimeString();
                    certExpiryDate = certificate.NotAfter.ToShortDateString() + " " + certificate.NotAfter.ToShortTimeString();
                }
                catch (Exception ex)
                {
                    errorString = ex.ToString();
                }
                finally 
                {
                    isValidCert = IsValidClientCertificate();
                    if (!isValidCert) Response.StatusCode = 403;
                    else Response.StatusCode = 200;
                }
            }
            else
            {
                certHeader = "";
            }
        }

        //
        // This is a SAMPLE verification routine. Depending on your application logic and security requirements, 
        // you should modify this method
        //
        private bool IsValidClientCertificate()
        {
            // In this example we will only accept the certificate as a valid certificate if all the conditions below are met:
            // 1. The certificate is not expired and is active for the current time on server.
            // 2. The subject name of the certificate has the common name nildevecc
            // 3. The issuer name of the certificate has the common name nildevecc and organization name Microsoft Corp
            // 4. The thumbprint of the certificate is 30757A2E831977D8BD9C8496E4C99AB26CB9622B
            //
            // This example does NOT test that this certificate is chained to a Trusted Root Authority (or revoked) on the server 
            // and it allows for self signed certificates
            //

            if (certificate == null || !String.IsNullOrEmpty(errorString)) return false;

            // 1. Check time validity of certificate
            if (DateTime.Compare(DateTime.Now, certificate.NotBefore) < 0 || DateTime.Compare(DateTime.Now, certificate.NotAfter) > 0) return false;

            // 2. Check subject name of certificate
            bool foundSubject = false;
            string[] certSubjectData = certificate.Subject.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string s in certSubjectData)
            {
                if (String.Compare(s.Trim(), "CN=nildevecc") == 0)
                {
                    foundSubject = true;
                    break;
                }
            }
            if (!foundSubject) return false;

            // 3. Check issuer name of certificate
            bool foundIssuerCN = false, foundIssuerO = false;
            string[] certIssuerData = certificate.Issuer.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string s in certIssuerData)
            {
                if (String.Compare(s.Trim(), "CN=nildevecc") == 0)
                {
                    foundIssuerCN = true;
                    if (foundIssuerO) break;
                }

                if (String.Compare(s.Trim(), "O=Microsoft Corp") == 0)
                {
                    foundIssuerO = true;
                    if (foundIssuerCN) break;
                }
            }

            if (!foundIssuerCN || !foundIssuerO) return false;

            // 4. Check thumprint of certificate
            if (String.Compare(certificate.Thumbprint.Trim().ToUpper(), "30757A2E831977D8BD9C8496E4C99AB26CB9622B") != 0) return false;

            // If you also want to test if the certificate chains to a Trusted Root Authority you can uncomment the code below
            //
            //X509Chain certChain = new X509Chain();
            //certChain.Build(certificate);
            //bool isValidCertChain = true;
            //foreach (X509ChainElement chElement in certChain.ChainElements)
            //{
            //    if (!chElement.Certificate.Verify())
            //    {
            //        isValidCertChain = false;
            //        break;
            //    }
            //}
            //if (!isValidCertChain) return false;

            return true;
        }
    }
}