Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Important
À compter du 28 juillet 2025, les modifications apportées aux certificats managés App Service (ASMC) affectent la façon dont les certificats sont émis et renouvelés dans certains scénarios. Bien que la plupart des clients n’ont pas besoin d’agir, nous vous recommandons de consulter notre billet de blog détaillé ASMC pour plus d’informations.
Vous pouvez restreindre l’accès à votre application Azure App Service en activant différents types d’authentification pour l’application. Une façon de configurer l’authentification consiste à demander un certificat client lorsque la demande cliente est envoyée à l’aide du protocole TLS (Transport Layer Security) / Secure Sockets Layer (SSL) et de valider le certificat. Ce mécanisme est appelé authentification mutuelle ou authentification par certificat client. Cet article montre comment configurer votre application pour utiliser l’authentification par certificat client.
Remarque
Votre code d’application doit valider le certificat client. App Service ne fait rien avec le certificat client autre que le transférer à votre application.
Si vous accédez à votre site via HTTP et non HTTPS, vous ne recevez aucun certificat client. Si votre application nécessite des certificats clients, vous ne devez pas autoriser les demandes adressées à votre application via HTTP.
Préparation de votre application web
Si vous souhaitez créer des liaisons TLS/SSL personnalisées ou activer des certificats clients pour votre application App Service, votre plan App Service doit se trouver dans les niveaux De base, Standard, Premium ou Isolé.
Pour vous assurer que votre application web se trouve dans un niveau tarifaire pris en charge :
Accédez à votre application web
Dans la zone de recherche du portail Azure , entrez App Services , puis sélectionnez-le dans les résultats de la recherche.
Dans la page App Services , sélectionnez votre application web :
Vous êtes maintenant sur la page de gestion de votre application web.
Vérification du niveau tarifaire
Dans le menu de gauche de votre application web, sous Paramètres, sélectionnez Scale-up (plan App Service).
Assurez-vous que votre application web n’est pas au niveau F1 ou D1. Ces niveaux ne prennent pas en charge de TLS/SSL personnalisé.
Si vous avez besoin de monter en puissance, consultez la section ci-après. Sinon, fermez le volet Scale-up et ignorez la section suivante.
Évolution de votre plan App Service
Sélectionnez un niveau payant, comme B1, B2, B3, ou n’importe quel niveau dans la catégorie Production.
Lorsque vous avez terminé, choisissez Sélectionner.
Une fois l’opération de mise à l’échelle terminée, vous verrez un message indiquant que le plan a été mis à jour.
Activer les certificats clients
Lorsque vous activez les certificats clients pour votre application, vous devez sélectionner votre choix de mode de certificat client. Le mode définit la façon dont votre application gère les certificats clients entrants. Les modes sont décrits dans le tableau suivant :
| Mode de certificat client | Descriptif |
|---|---|
| Obligatoire | Toutes les requêtes nécessitent un certificat client. |
| Facultatif | Les demandes peuvent utiliser un certificat client. Les clients sont invités à entrer un certificat par défaut. Par exemple, les clients de navigateur affichent une invite pour sélectionner un certificat pour l’authentification. |
| Utilisateur interactif facultatif | Les demandes peuvent utiliser un certificat client. Les clients ne sont pas invités à entrer un certificat par défaut. Par exemple, les clients de navigateur n’affichent pas d’invite pour sélectionner un certificat pour l’authentification. |
Pour utiliser le portail Azure pour activer les certificats clients :
- Accédez à la page de gestion des applications.
- Dans le menu de gauche, sélectionnezParamètres généraux>.
- Pour le mode certificat client, sélectionnez votre choix.
- Cliquez sur Enregistrer.
Exclure les chemins d’accès nécessitant une authentification
Lorsque vous activez l’authentification mutuelle pour votre application, tous les chemins sous la racine de votre application nécessitent un certificat client pour l’accès. Pour lever cette exigence pour certains chemins d’accès, définissez des chemins d’exclusion dans le cadre de la configuration de votre application.
Remarque
L'utilisation de n'importe quel chemin d'exclusion de certificat client déclenche une renégociation TLS pour les demandes entrantes vers l'application.
Dans le menu de gauche de la page de gestion des applications, sélectionnez Configuration des paramètres>. Sélectionnez l’onglet Paramètres généraux.
À côté de Chemins d’accès d’exclusion de certificat, sélectionnez l’icône crayon.
Sélectionnez Nouveau chemin, spécifiez un chemin d’accès ou une liste de chemins séparés par
,ou;, puis sélectionnez OK.Cliquez sur Enregistrer.
La capture d’écran suivante montre comment définir un chemin d’exclusion de certificat. Dans cet exemple, tout chemin d’accès de l’application qui commence par /public ne demande pas de certificat client. La correspondance de chemin d’accès n’est pas spécifique au cas.
Certificat client et renégociation TLS
Pour certains paramètres de certificat client, App Service nécessite la renégociation TLS pour lire une requête avant de savoir s’il faut demander un certificat client. Les deux paramètres suivants déclenchent la renégociation TLS :
- Utilisation du mode de certificat client utilisateur interactif facultatif .
- Utilisation d’un chemin d’exclusion de certificat client.
Remarque
TLS 1.3 et HTTP 2.0 ne prennent pas en charge la renégociation TLS. Ces protocoles ne fonctionnent pas si votre application est configurée avec les paramètres de certificat client qui utilisent la renégociation TLS.
Pour désactiver la renégociation TLS et que l’application négocie les certificats clients lors de l’établissement d’une liaison TLS, vous devez effectuer les actions suivantes dans votre application :
- Définissez le mode de certificat client sur Obligatoire ou Facultatif.
- Supprimez tous les chemins d’exclusion de certificat client.
Télécharger des fichiers volumineux avec une renégociation TLS
Les configurations de certificat client qui utilisent la renégociation TLS ne peuvent pas prendre en charge les demandes entrantes avec des fichiers dont la taille est supérieure à 100 Ko. Cette limite est due à des limitations de taille de mémoire tampon. Dans ce scénario, toutes les requêtes POST ou PUT qui sont supérieures à 100 Ko échouent avec une erreur 403. Cette limite n'est pas configurable et ne peut pas être augmentée.
Pour répondre à la limite de 100 Ko, tenez compte des solutions suivantes :
- Désactiver la renégociation TLS. Effectuez les actions suivantes dans les configurations de certificat client de votre application :
- Définissez le mode de certificat client sur Obligatoire ou Facultatif.
- Supprimez tous les chemins d’exclusion de certificat client.
- Envoyer une requête HEAD avant la requête PUT/POST. La requête HEAD traite le certificat du client.
- Ajoutez l’en-tête
Expect: 100-Continueà votre requête. Cet en-tête entraîne l’attente du client jusqu’à ce que le serveur réponde avec un100 Continueavant d’envoyer le corps de la requête et que les mémoires tampons soient ignorées.
Accéder au certificat client
Dans App Service, l’arrêt TLS de la requête se produit au niveau de l’équilibreur de charge frontal. Lorsque App Service transfère la requête à votre code d’application avec les certificats clients activés, il injecte un en-tête de requête X-ARR-ClientCert avec le certificat client. App Service ne fait rien avec ce certificat client autre que de le transférer à votre application. Votre code d’application doit valider le certificat client.
Dans ASP.NET, le certificat client est disponible via la HttpRequest.ClientCertificate propriété.
Dans d’autres piles d’applications (Node.js, PHP), le certificat client est disponible via une valeur codée en base64 dans l’en-tête X-ARR-ClientCert de requête.
Exemple ASP.NET Core
Pour ASP.NET Core, l’intergiciel est disponible pour analyser les certificats transférés. Un intergiciel distinct est disponible pour utiliser les en-têtes de protocole transférés. Les deux doivent être présents pour que les certificats transférés soient acceptés. Vous pouvez placer une logique de validation de certificat personnalisée dans les options 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?}");
});
}
}
Un exemple de formulaires Web ASP.NET
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;
}
}
}
Exemple Node.js
L’exemple de code Node.js suivant obtient l’en-tête X-ARR-ClientCert et utilise node-forge pour convertir la chaîne PEM (Privacy Enhanced Mail) codée en Base64 en un objet de certificat et le valider :
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);
}
}
}
}
Exemple Java
La classe Java suivante encode le certificat en passant d’une instance X-ARR-ClientCert à une instance X509Certificate. certificateIsValid() confirme que l’empreinte du certificat correspond à celle fournie dans le constructeur et que le certificat n’a pas expiré.
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;
}
}
Exemple de code Python
Les exemples de code Python Flask et Django suivants implémentent un élément décoratif nommé authorize_certificate qui peut être utilisé sur une fonction d’affichage pour autoriser l’accès uniquement aux appelants qui présentent un certificat client valide. Il attend un certificat au format PEM dans l’en-tête X-ARR-ClientCert et utilise le package de chiffrement Python pour valider le certificat en fonction de son empreinte digitale (empreinte numérique), du nom commun de l’objet, du nom commun de l’émetteur et des dates de début et d’expiration. Si la validation échoue, l’élément décoratif garantit qu’une réponse HTTP avec le code d’état 403 (Interdit) est retournée au client.
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
L’extrait de code suivant montre comment utiliser l’élément décoratif sur une fonction de vue Flask.
@app.route('/hellocert')
@authorize_certificate
def hellocert():
print('Request for hellocert page received')
return render_template('index.html')
