Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Viktigt!
Från och med den 28 juli 2025 påverkar ändringar av App Service Managed Certificates (ASMC) hur certifikat utfärdas och förnyas i vissa scenarier. Även om de flesta kunder inte behöver vidta åtgärder rekommenderar vi att du läser vårt asmc-detaljerade blogginlägg för mer information.
Du kan begränsa åtkomsten till din Azure App Service-app genom att aktivera olika typer av autentisering för appen. Ett sätt att konfigurera autentisering är att begära ett klientcertifikat när klientbegäran skickas med hjälp av TLS (Transport Layer Security)/SSL (Secure Sockets Layer) och verifiera certifikatet. Den här mekanismen kallas ömsesidig autentisering eller klientcertifikatautentisering. I artikeln beskrivs hur du konfigurerar din app till att använda autentisering med klientcertifikat.
Anmärkning
Din appkod måste verifiera klientcertifikatet. App Service gör inget annat med klientcertifikatet än att vidarebefordra det till din app.
Om du kommer åt webbplatsen via HTTP och inte HTTPS får du inga klientcertifikat. Om programmet kräver klientcertifikat bör du inte tillåta begäranden till ditt program via HTTP.
Förbereda din webbapp
Om du vill skapa anpassade TLS/SSL-bindningar eller aktivera klientcertifikat för din App Service-app måste App Service-planen ligga på nivåerna Basic, Standard, Premium eller Isolerad.
Så här ser du till att webbappen finns på en prisnivå som stöds:
Gå till din webbapp
- I sökrutan i Azure-portalen anger du App Services och väljer det sedan i sökresultaten. 
- På sidan App Services väljer du din webbapp:   - Nu är du på webbappens hanteringssida. 
Kontrollera prisnivån
- I den vänstra menyn för webbappen går du till Inställningar och väljer Skala upp (App Service-plan). 
- Kontrollera att webbappen inte finns på F1- eller D1-nivån. De här nivåerna stöder inte anpassad TLS/SSL. 
- Om du behöver skala upp följer du stegen i nästa avsnitt. Annars stänger du fönstret Skala upp och hoppar över nästa avsnitt. 
Skala upp App Service-planen
- Välj valfri icke-kostnadsfri nivå, till exempel B1, B2, B3 eller någon annan nivå i kategorin Produktion . 
- När du är klar väljer du Välj. - När skalningsåtgärden är klar visas ett meddelande om att planen har uppdaterats. 
Aktivera klientcertifikat
När du aktiverar klientcertifikat för din app bör du välja val av klientcertifikatläge. Läget definierar hur appen hanterar inkommande klientcertifikat. Lägena beskrivs i följande tabell:
| Klientcertifikatläge | beskrivning | 
|---|---|
| Obligatoriskt | Alla begäranden kräver ett klientcertifikat. | 
| Valfritt | Begäranden kan använda ett klientcertifikat. Klienter uppmanas att ange ett certifikat som standard. Webbläsarklienter visar till exempel en uppmaning om att välja ett certifikat för autentisering. | 
| Valfri interaktiv användare | Begäranden kan använda ett klientcertifikat. Klienter uppmanas inte att ange ett certifikat som standard. Webbläsarklienter visar till exempel inte någon uppmaning om att välja ett certifikat för autentisering. | 
Så här använder du Azure-portalen för att aktivera klientcertifikat:
- Gå till sidan för apphantering.
- I den vänstra menyn väljer du Allmänna inställningar för konfiguration>.
- För Klientcertifikatläge väljer du ditt val.
- Välj Spara.
Undanta sökvägar från att kräva autentisering
När du aktiverar ömsesidig autentisering för ditt program kräver alla sökvägar under appens rot ett klientcertifikat för åtkomst. Om du vill ta bort det här kravet för vissa sökvägar definierar du undantagssökvägar som en del av programkonfigurationen.
Anmärkning
Om du använder en sökväg för undantag för klientcertifikat utlöses TLS-omförhandling för inkommande begäranden till appen.
- I den vänstra menyn på apphanteringssidan väljer du Inställningar>Konfiguration. Välj fliken Allmänt inställningar. 
- Bredvid Sökvägar för certifikatundantag väljer du pennikonen. 
- Välj Ny sökväg, ange en sökväg eller en lista över sökvägar avgränsade med - ,eller- ;och välj sedan OK.
- Välj Spara. 
Följande skärmbild visar hur du anger en sökväg för certifikatundantag. I det här exemplet begär inte någon sökväg för appen som börjar med /public ett klientcertifikat. Sökvägsmatchning är inte skiftlägesspecifik.
Klientcertifikat och TLS-omförhandling
För vissa klientcertifikatinställningar kräver App Service TLS-omförhandling för att läsa en begäran innan du vet om du vill fråga efter ett klientcertifikat. Båda följande inställningar utlöser TLS-omförhandling:
- Använd det valfria klientcertifikatläget för interaktiv användare .
- Använda en sökväg för klientcertifikatsundantag.
Anmärkning
TLS 1.3 och HTTP 2.0 stöder inte TLS-omförhandling. Dessa protokoll fungerar inte om din app har konfigurerats med klientcertifikatinställningar som använder TLS-omförhandling.
Om du vill inaktivera TLS-omförhandling och låta appen förhandla om klientcertifikat under TLS-handskakningen måste du vidta följande åtgärder i din app:
- Ange klientcertifikatläget till Obligatoriskt eller Valfritt.
- Ta bort alla undantag för klientcertifikat.
Ladda upp stora filer med TLS-omförhandling
Klientcertifikatkonfigurationer som använder TLS-omförhandling kan inte stödja inkommande begäranden med filer som är större än 100 kB. Den här gränsen orsakas av begränsningar i buffertstorleken. I det här scenariot misslyckas alla POST- eller PUT-begäranden som är över 100 KB med ett 403-fel. Den här gränsen kan inte konfigureras och kan inte ökas.
Tänk på följande lösningar för att åtgärda gränsen på 100 KB:
- Inaktivera TLS-omförhandling. Utför följande åtgärder i appens klientcertifikatkonfigurationer: - Ange klientcertifikatläget till Obligatoriskt eller Valfritt.
- Ta bort alla undantag för klientcertifikat.
 
- Skicka en HEAD-begäran före PUT/POST-begäran. HEAD-begäran hanterar klientcertifikatet.
- Lägg till headern Expect: 100-Continuei din begäran. Det här huvudet gör att klienten väntar tills servern svarar med en100 Continueinnan begärandetexten skickas och buffertarna kringgås.
Få åtkomst till klientcertifikatet
I App Service sker TLS-avslutningen av begäran i frontend-lastbalanseraren. När App Service vidarebefordrar en begäran till din appkod med klientcertifikat aktiverade, lägger den in en X-ARR-ClientCert begäranderubrik med klientcertifikatet. App Service gör inget annat med det här klientcertifikatet än att vidarebefordra det till din app. Din appkod måste verifiera klientcertifikatet.
I ASP.NET är klientcertifikatet tillgängligt via egenskapen HttpRequest.ClientCertificate .
I andra programstackar (Node.js, PHP) är klientcertifikatet tillgängligt via ett Base64-kodat värde i X-ARR-ClientCert begärandehuvudet.
ASP.NET Core-exempel
För ASP.NET Core är mellanprogram tillgängliga för att parsa vidarebefordrade certifikat. Separata mellanprogram är tillgängliga för användning av de vidarebefordrade protokollrubrikerna. Båda måste finnas för att vidarebefordrade certifikat ska accepteras. Du kan placera anpassad certifikatverifieringslogik i alternativen för CertificateAuthentication:
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    public IConfiguration Configuration { get; }
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        // Configure the application to use the protocol and client IP address forwarded by the front-end load balancer.
        services.Configure<ForwardedHeadersOptions>(options =>
        {
            options.ForwardedHeaders =
                ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
            // By default, only loopback proxies are allowed. Clear that restriction to enable this explicit configuration.
            options.KnownNetworks.Clear();
            options.KnownProxies.Clear();
        });       
        
        // Configure the application to use the client certificate forwarded by the front-end load balancer.
        services.AddCertificateForwarding(options => { options.CertificateHeader = "X-ARR-ClientCert"; });
        // Add certificate authentication so that when authorization is performed the user will be created from the certificate.
        services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate();
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        
        app.UseForwardedHeaders();
        app.UseCertificateForwarding();
        app.UseHttpsRedirection();
        app.UseAuthentication()
        app.UseAuthorization();
        app.UseStaticFiles();
        app.UseRouting();
        
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}
ASP.NET exempel på webbformulär
    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. You should modify this method to suit  your application logic and security requirements. 
            // 
            //
            private bool IsValidClientCertificate()
            {
                // In this example, the certificate is accepted as a valid certificate only if these conditions are met:
                // - The certificate isn't expired and is active for the current time on the server.
                // - The subject name of the certificate has the common name nildevecc.
                // - The issuer name of the certificate has the common name nildevecc and the organization name Microsoft Corp.
                // - The thumbprint of the certificate is 30757A2E831977D8BD9C8496E4C99AB26CB9622B.
                //
                // This example doesn't test that the certificate is chained to a trusted root authority (or revoked) on the server. 
                // It allows self-signed certificates.
                //
                if (certificate == null || !String.IsNullOrEmpty(errorString)) return false;
                // 1. Check time validity of the certificate.
                if (DateTime.Compare(DateTime.Now, certificate.NotBefore) < 0 || DateTime.Compare(DateTime.Now, certificate.NotAfter) > 0) return false;
                // 2. Check the subject name of the 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 the issuer name of the 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 the thumbprint of the certificate.
                if (String.Compare(certificate.Thumbprint.Trim().ToUpper(), "30757A2E831977D8BD9C8496E4C99AB26CB9622B") != 0) return false;
                return true;
            }
        }
    }
Node.js exempel
Följande Node.js exempelkod hämtar X-ARR-ClientCert huvudet och använder node-forge för att konvertera den Base64-kodade Privacy Enhanced Mail (PEM)-strängen till ett certifikatobjekt och verifiera det.
import { NextFunction, Request, Response } from 'express';
import { pki, md, asn1 } from 'node-forge';
export class AuthorizationHandler {
    public static authorizeClientCertificate(req: Request, res: Response, next: NextFunction): void {
        try {
            // Get header.
            const header = req.get('X-ARR-ClientCert');
            if (!header) throw new Error('UNAUTHORIZED');
            // Convert from PEM to PKI certificate.
            const pem = `-----BEGIN CERTIFICATE-----${header}-----END CERTIFICATE-----`;
            const incomingCert: pki.Certificate = pki.certificateFromPem(pem);
            // Validate certificate thumbprint.
            const fingerPrint = md.sha1.create().update(asn1.toDer(pki.certificateToAsn1(incomingCert)).getBytes()).digest().toHex();
            if (fingerPrint.toLowerCase() !== 'abcdef1234567890abcdef1234567890abcdef12') throw new Error('UNAUTHORIZED');
            // Validate time validity.
            const currentDate = new Date();
            if (currentDate < incomingCert.validity.notBefore || currentDate > incomingCert.validity.notAfter) throw new Error('UNAUTHORIZED');
            // Validate issuer.
            if (incomingCert.issuer.hash.toLowerCase() !== 'abcdef1234567890abcdef1234567890abcdef12') throw new Error('UNAUTHORIZED');
            // Validate subject.
            if (incomingCert.subject.hash.toLowerCase() !== 'abcdef1234567890abcdef1234567890abcdef12') throw new Error('UNAUTHORIZED');
            next();
        } catch (e) {
            if (e instanceof Error && e.message === 'UNAUTHORIZED') {
                res.status(401).send();
            } else {
                next(e);
            }
        }
    }
}
Java-exempel
Följande Java-klass kodar certifikatet från X-ARR-ClientCert till en X509Certificate instans. 
              certificateIsValid() verifierar att certifikatets tumavtryck matchar det som anges i konstruktorn och att certifikatet inte har upphört att gälla.
import java.io.ByteArrayInputStream;
import java.security.NoSuchAlgorithmException;
import java.security.cert.*;
import java.security.MessageDigest;
import sun.security.provider.X509Factory;
import javax.xml.bind.DatatypeConverter;
import java.util.Base64;
import java.util.Date;
public class ClientCertValidator { 
    private String thumbprint;
    private X509Certificate certificate;
    /**
     * Constructor.
     * @param certificate. The certificate from the "X-ARR-ClientCert" HTTP header.
     * @param thumbprint. The thumbprint to check against.
     * @throws CertificateException if the certificate factory can't be created.
     */
    public ClientCertValidator(String certificate, String thumbprint) throws CertificateException {
        certificate = certificate
                .replaceAll(X509Factory.BEGIN_CERT, "")
                .replaceAll(X509Factory.END_CERT, "");
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        byte [] base64Bytes = Base64.getDecoder().decode(certificate);
        X509Certificate X509cert =  (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(base64Bytes));
        this.setCertificate(X509cert);
        this.setThumbprint(thumbprint);
    }
    /**
     * Check that the certificate's thumbprint matches the one given in the constructor, and that the
     * certificate isn't expired.
     * @return True if the certificate's thumbprint matches and isn't expired. False otherwise.
     */
    public boolean certificateIsValid() throws NoSuchAlgorithmException, CertificateEncodingException {
        return certificateHasNotExpired() && thumbprintIsValid();
    }
    /**
     * Check certificate's timestamp.
     * @return True if the certificate isn't expired. It returns False if it is expired.
     */
    private boolean certificateHasNotExpired() {
        Date currentTime = new java.util.Date();
        try {
            this.getCertificate().checkValidity(currentTime);
        } catch (CertificateExpiredException | CertificateNotYetValidException e) {
            return false;
        }
        return true;
    }
    /**
     * Check whether the certificate's thumbprint matches the given one.
     * @return True if the thumbprints match. False otherwise.
     */
    private boolean thumbprintIsValid() throws NoSuchAlgorithmException, CertificateEncodingException {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] der = this.getCertificate().getEncoded();
        md.update(der);
        byte[] digest = md.digest();
        String digestHex = DatatypeConverter.printHexBinary(digest);
        return digestHex.toLowerCase().equals(this.getThumbprint().toLowerCase());
    }
    // Getters and setters.
    public void setThumbprint(String thumbprint) {
        this.thumbprint = thumbprint;
    }
    public String getThumbprint() {
        return this.thumbprint;
    }
    public X509Certificate getCertificate() {
        return certificate;
    }
    public void setCertificate(X509Certificate certificate) {
        this.certificate = certificate;
    }
}
Python-exempel
Följande Flask- och Django Python-kodexempel implementerar en dekoratör med namnet authorize_certificate som kan användas i en vyfunktion för att endast tillåta åtkomst till anropare som presenterar ett giltigt klientcertifikat. Det förväntar sig ett PEM-formaterat certifikat i X-ARR-ClientCert huvudet och använder Python-kryptografipaketet för att verifiera certifikatet baserat på dess fingeravtryck (tumavtryck), ämnesnamn, utfärdarens gemensamma namn och start- och förfallodatum. Om verifieringen misslyckas ser dekoratören till att ett HTTP-svar med statuskod 403 (förbjudet) returneras till klienten.
from functools import wraps
from datetime import datetime, timezone
from flask import abort, request
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
def validate_cert(request):
    try:
        cert_value =  request.headers.get('X-ARR-ClientCert')
        if cert_value is None:
            return False
        
        cert_data = ''.join(['-----BEGIN CERTIFICATE-----\n', cert_value, '\n-----END CERTIFICATE-----\n',])
        cert = x509.load_pem_x509_certificate(cert_data.encode('utf-8'))
    
        fingerprint = cert.fingerprint(hashes.SHA1())
        if fingerprint != b'12345678901234567890':
            return False
        
        subject = cert.subject
        subject_cn = subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
        if subject_cn != "contoso.com":
            return False
        
        issuer = cert.issuer
        issuer_cn = issuer.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
        if issuer_cn != "contoso.com":
            return False
    
        current_time = datetime.now(timezone.utc)
    
        if current_time < cert.not_valid_before_utc:
            return False
        
        if current_time > cert.not_valid_after_utc:
            return False
        
        return True
    except Exception as e:
        # Handle any errors encountered during validation.
        print(f"Encountered the following error during certificate validation: {e}")
        return False
    
def authorize_certificate(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not validate_cert(request):
            abort(403)
        return f(*args, **kwargs)
    return decorated_function
Följande kodfragment visar hur du använder dekoratören på en Flask-vyfunktion.
@app.route('/hellocert')
@authorize_certificate
def hellocert():
   print('Request for hellocert page received')
   return render_template('index.html')
