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.
TLS (Transport Layer Security) est un protocole de chiffrement conçu pour sécuriser la communication entre deux ordinateurs via Internet. Le protocole TLS est exposé dans .NET via la SslStream classe.
Cet article présente les meilleures pratiques pour configurer la communication sécurisée entre le client et le serveur et suppose l’utilisation de .NET. Pour connaître les meilleures pratiques avec .NET Framework, consultez les meilleures pratiques tls (Transport Layer Security) avec .NET Framework.
Sélectionner la version TLS
Bien qu’il soit possible de spécifier la version du protocole TLS à utiliser via la EnabledSslProtocols propriété, il est recommandé de s'en remettre aux paramètres du système d’exploitation à l’aide de la valeur None (il s’agit de la valeur par défaut).
Remettre la décision au système d'exploitation utilise automatiquement la version la plus récente de TLS disponible et permet à l'application de récupérer les modifications après les mises à jour du système d'exploitation. Le système d’exploitation peut également empêcher l’utilisation de versions TLS qui ne sont plus considérées comme sécurisées.
Sélectionner des suites de chiffrement
SslStream permet aux utilisateurs de spécifier les suites de chiffrement qui peuvent être négociées par l’établissement d’une liaison TLS via la CipherSuitesPolicy classe. Comme avec les versions TLS, il est recommandé de laisser le système d’exploitation décider qui sont les meilleures suites de chiffrement avec lesquelles négocier, et par conséquent, il est recommandé d’éviter d’utiliser CipherSuitesPolicy.
Remarque
CipherSuitesPolicy n’est pas pris en charge sur Windows et les tentatives d’instanciation entraînent la levée d’une NotSupportedException.
Spécifier un certificat local
Lors de l’authentification en tant que serveur, SslStream nécessite toujours un certificat. Lors de l’authentification en tant que client, vous fournissez également un certificat si le serveur en demande un pour tls mutuel (mTLS). Dans les deux rôles, le certificat doit être une X509Certificate2 instance qui contient la clé privée.
Les versions récentes .NET gèrent les côtés du serveur et du client de manière symétrique. Les instructions suivantes s’appliquent donc si l’application s’authentifie en tant que serveur, client ou les deux.
Vous pouvez fournir le certificat à SslStream de plusieurs façons.
Lorsque vous vous authentifiez en tant que serveur :
- Définissez la SslServerAuthenticationOptions.ServerCertificate propriété ou transmettez le certificat à SslStream.AuthenticateAsServerAsync.
- Retournez le certificat depuis le SslServerAuthenticationOptions.ServerCertificateSelectionCallback callback.
- Définissez une SslStreamCertificateContext valeur sur la SslServerAuthenticationOptions.ServerCertificateContext propriété.
Lorsque vous vous authentifiez en tant que client :
- Ajoutez le certificat à la collection SslClientAuthenticationOptions.ClientCertificates, ou passez à SslStream.AuthenticateAsClientAsync une collection qui le contient.
- Retournez le certificat dans la fonction de rappel SslClientAuthenticationOptions.LocalCertificateSelectionCallback.
- Définissez une SslStreamCertificateContext valeur sur la SslClientAuthenticationOptions.ClientCertificateContext propriété.
Remarque
La ClientCertificateContext propriété est disponible à partir de .NET 8.
Pour de meilleures performances, utilisez la propriété de contexte de certificat (ServerCertificateContext ou ClientCertificateContext). Lorsque vous fournissez le certificat de l’une des autres façons, SslStream crée un SslStreamCertificateContext certificat en interne. La création du contexte génère un X509Chain, ce qui est une opération gourmande en ressources processeur. Il est donc plus efficace de créer le contexte une seule fois et de le réutiliser dans plusieurs instances de SslStream.
La réutilisation d’une SslStreamCertificateContext instance active également des fonctionnalités supplémentaires telles que la reprise de session TLS sur les serveurs Linux.
Envoyer des certificats intermédiaires au pair
Lorsqu’une autorité de certification intermédiaire émet le certificat local, l’homologue peut ne pas être en mesure de générer la chaîne de certificats complète, sauf si l’établissement d’une liaison inclut les certificats intermédiaires. Pour envoyer ces intermédiaires, créez une SslStreamCertificateContext avec la Create méthode et transmettez les certificats intermédiaires dans le additionalCertificates paramètre :
X509Certificate2 leafCertificate = GetLeafCertificate();
X509Certificate2Collection intermediates = GetIntermediateCertificates();
SslStreamCertificateContext certificateContext =
SslStreamCertificateContext.Create(leafCertificate, intermediates);
// When you authenticate as a server.
serverOptions.ServerCertificateContext = certificateContext;
// When you authenticate as a client for mutual TLS.
clientOptions.ClientCertificateContext = certificateContext;
Le contexte fonctionne de la même façon pour les deux rôles. Côté client, le contexte du certificat est la méthode recommandée pour transmettre les certificats intermédiaires, car l’autre solution — ajouter les certificats intermédiaires au magasin de certificats de l’ordinateur ou de l’utilisateur — a une incidence sur toutes les applications du système.
Validation personnalisée X509Certificate
Il existe certains scénarios dans lesquels la procédure de validation de certificat par défaut n’est pas adéquate et une logique de validation personnalisée est requise. Les parties de la logique de validation peuvent être personnalisées en spécifiant SslClientAuthenticationOptions.CertificateChainPolicy ou SslServerAuthenticationOptions.CertificateChainPolicy. Vous pouvez également fournir une logique complètement personnalisée via la <propriété System.Net.Security.SslClientAuthenticationOptions.RemoteCertificateValidationCallback> . Pour plus d'informations, consultez Confiance des certificats personnalisés.
Approbation de certificat personnalisée
Lorsque vous rencontrez un certificat qui n’a pas été émis par les autorités de certification approuvées par l’ordinateur (y compris les certificats auto-signés), la procédure de validation de certificat par défaut échoue. Pour résoudre ce problème, vous pouvez ajouter les certificats d’émetteur nécessaires au magasin approuvé de l’ordinateur. Toutefois, cela peut affecter d’autres applications sur le système et n’est pas toujours possible.
La solution alternative consiste à spécifier des certificats racines de confiance personnalisés via un X509ChainPolicy. Pour spécifier une liste d’approbation personnalisée qui sera utilisée au lieu de la liste d’approbations système lors de la validation, considérez l’exemple suivant :
SslClientAuthenticationOptions clientOptions = new();
clientOptions.CertificateChainPolicy = new X509ChainPolicy()
{
TrustMode = X509ChainTrustMode.CustomRootTrust,
CustomTrustStore =
{
customIssuerCert
}
};
Les clients configurés avec la stratégie précédente acceptent uniquement les certificats approuvés par customIssuerCert.
Ignorer les erreurs de validation spécifiques
Envisagez un appareil IoT sans horloge persistante. Après la mise sous tension, l’horloge de l’appareil démarrerait plusieurs années dans le passé et, par conséquent, tous les certificats seraient considérés comme « non encore valides ». Considérez le code suivant qui montre une implémentation de rappel de validation ignorant les violations de période de validité.
static bool CustomCertificateValidationCallback(
object sender,
X509Certificate? certificate,
X509Chain? chain,
SslPolicyErrors sslPolicyErrors)
{
// Anything that would have been accepted by default is OK
if (sslPolicyErrors == SslPolicyErrors.None)
{
return true;
}
// If there is something wrong other than a chain processing error, don't trust it.
if (sslPolicyErrors != SslPolicyErrors.RemoteCertificateChainErrors)
{
return false;
}
Debug.Assert(chain is not null);
// If the reason for RemoteCertificateChainError is that the chain built empty, don't trust it.
if (chain.ChainStatus.Length == 0)
{
return false;
}
foreach (X509ChainStatus status in chain.ChainStatus)
{
// If an error other than `NotTimeValid` (or `NoError`) is present, don't trust it.
if ((status.Status & ~X509ChainStatusFlags.NotTimeValid) != X509ChainStatusFlags.NoError)
{
return false;
}
}
return true;
}
Épinglage de certificat
Une autre situation où la validation de certificat personnalisée est nécessaire lorsque les clients s’attendent à ce que les serveurs utilisent un certificat spécifique ou qu’un certificat d’un petit ensemble de certificats connus. Cette pratique est appelée épinglage de certificat. L’extrait de code suivant montre un rappel de validation qui vérifie que le serveur présente un certificat avec une clé publique connue spécifique.
static bool CustomCertificateValidationCallback(
object sender,
X509Certificate? certificate,
X509Chain? chain,
SslPolicyErrors sslPolicyErrors)
{
// If there is something wrong other than a chain processing error, don't trust it.
if ((sslPolicyErrors & ~SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
return false;
}
Debug.Assert(certificate is not null);
const string ExpectedPublicKey =
"3082010A0282010100C204ECF88CEE04C2B3D850D57058CC9318EB5C" +
"A86849B022B5F9959EB12B2C763E6CC04B604C4CEAB2B4C00F80B6B0" +
"F972C98602F95C415D132B7F71C44BBCE9942E5037A6671C618CF641" +
"42C546D31687279F74EB0A9D11522621736C844C7955E4D16BE8063D" +
"481552ADB328DBAAFF6EFF60954A776B39F124D131B6DD4DC0C4FC53" +
"B96D42ADB57CFEAEF515D23348E72271C7C2147A6C28EA374ADFEA6C" +
"B572B47E5AA216DC69B15744DB0A12ABDEC30F47745C4122E19AF91B" +
"93E6AD2206292EB1BA491C0C279EA3FB8BF7407200AC9208D98C5784" +
"538105CBE6FE6B5498402785C710BB7370EF6918410745557CF9643F" +
"3D2CC3A97CEB931A4C86D1CA850203010001";
return certificate.GetPublicKeyString().Equals(ExpectedPublicKey);
}
Considérations relatives à la validation des certificats clients
Les applications serveur doivent être prudentes lors de la nécessité et de la validation des certificats clients. Les certificats peuvent contenir l’extension AIA (Authority Information Access) qui spécifie où le certificat émetteur peut être téléchargé. Le serveur peut donc tenter de télécharger le certificat émetteur à partir d’un serveur externe lors de la génération X509Chain du certificat client. De même, les serveurs peuvent avoir besoin de contacter des serveurs externes pour s’assurer que le certificat client n’a pas été révoqué.
La nécessité de contacter des serveurs externes lors de la génération et de la validation de X509Chain l’application peut exposer l’application à des attaques par déni de service si les serveurs externes sont lents à répondre. Par conséquent, les applications serveur doivent configurer le comportement de génération de X509Chain à l’aide du/de la CertificateChainPolicy.
Remarque
À compter de .NET 11, SslStream désactive les téléchargements de certificats AIA par défaut lors de la validation des certificats clients en tant que serveur. Si aucune valeur personnalisée CertificateChainPolicy n’est fournie, le serveur ne tente pas d’extraire les certificats intermédiaires manquants via AIA. Pour plus d’informations, consultez les téléchargements de certificats AIA côté serveur SslStream désactivés par défaut.