Freigeben über


Bewährte Methoden für TLS/SSL

TLS (Transport Layer Security) ist ein kryptografisches Protokoll zur Sicherung der Kommunikation zwischen zwei Computern über das Internet. Das TLS-Protokoll wird in .NET über die SslStream Klasse verfügbar gemacht.

In diesem Artikel werden bewährte Methoden zum Einrichten der sicheren Kommunikation zwischen Client und Server beschrieben und die Verwendung von .NET vorausgesetzt. Bewährte Methoden mit .NET Framework finden Sie unter " Transport Layer Security (TLS)"- bewährte Methoden mit .NET Framework.

TLS-Version auswählen

Obwohl es möglich ist, die Version des TLS-Protokolls über die EnabledSslProtocols-Eigenschaft anzugeben, wird empfohlen, sich auf die Einstellungen des Betriebssystems zu verlassen, indem der None Wert verwendet wird (dies ist die Standardeinstellung).

Durch das Zurückstellen der Entscheidung auf das Betriebssystem wird automatisch die neueste Version von TLS verwendet, und die Anwendung kann Änderungen nach Betriebssystemupgrades übernehmen. Das Betriebssystem kann auch die Verwendung von TLS-Versionen verhindern, die nicht mehr als sicher eingestuft werden.

Cipher-Suites auswählen

SslStream ermöglicht es Benutzern, festzulegen, welche Cipher-Suites vom TLS-Handshake über die CipherSuitesPolicy Klasse ausgehandelt werden können. Wie bei TLS-Versionen wird empfohlen, dem Betriebssystem die Entscheidung zu überlassen, welche die besten Suites mit Verschlüsselungsverfahren für die Aushandlung sind. Daher wird empfohlen, die Verwendung von CipherSuitesPolicy zu vermeiden.

Hinweis

CipherSuitesPolicy wird unter Windows nicht unterstützt. Der Versuch, es zu instanziieren, führt dazu, dass NotSupportedException ausgelöst wird.

Angeben eines Serverzertifikats

Für die Authentifizierung als Server SslStream ist eine X509Certificate2 Instanz erforderlich. Es wird empfohlen, immer eine X509Certificate2 Instanz zu verwenden, die auch den privaten Schlüssel enthält.

Es gibt mehrere Möglichkeiten, wie ein Serverzertifikat an SslStream übergeben werden kann.

Der empfohlene Ansatz besteht darin, die SslServerAuthenticationOptions.ServerCertificateContext Eigenschaft zu verwenden. Wenn das Zertifikat auf eine der beiden anderen Arten abgerufen wird, wird eine SslStreamCertificateContext Instanz intern durch die SslStream Implementierung erstellt. Das Erstellen eines SslStreamCertificateContext erfordert den Aufbau eines X509Chain, was eine CPU-intensive Operation ist. Es ist effizienter, ein SslStreamCertificateContext mal zu erstellen und es für mehrere SslStream Instanzen wiederzuverwenden.

Das Erneute Verwenden von SslStreamCertificateContext Instanzen ermöglicht auch zusätzliche Features wie die WIEDERaufnahme der TLS-Sitzung auf Linux-Servern.

Benutzerdefinierte X509Certificate-Überprüfung

Es gibt bestimmte Szenarien, in denen das Standardmäßige Zertifikatüberprüfungsverfahren nicht ausreichend ist und einige benutzerdefinierte Validierungslogik erforderlich ist. Teile der Validierungslogik können durch Angabe von SslClientAuthenticationOptions.CertificateChainPolicy oder SslServerAuthenticationOptions.CertificateChainPolicy angepasst werden. Alternativ kann eine vollständig benutzerdefinierte Logik über die Eigenschaft <System.Net.Security.SslClientAuthenticationOptions.RemoteCertificateValidationCallback> bereitgestellt werden. Weitere Informationen finden Sie unter Benutzerdefinierte Zertifikatvertrauensstellung.

Benutzerdefinierte Zertifikatvertrauensstellung

Beim Auftreten eines Zertifikats, das von keiner der vom Computer vertrauenswürdigen Zertifizierungsstellen (einschließlich selbstsignierter Zertifikate) ausgestellt wurde, schlägt die Standardmäßige Zertifikatüberprüfung fehl. Eine mögliche Möglichkeit, dies zu beheben, ist das Hinzufügen der erforderlichen Ausstellerzertifikate zum vertrauenswürdigen Speicher des Computers. Dies kann sich jedoch auf andere Anwendungen auf dem System auswirken und ist nicht immer möglich.

Die alternative Lösung besteht darin, benutzerdefinierte vertrauenswürdige Stammzertifikate über X509ChainPolicy anzugeben. Wenn Sie eine benutzerdefinierte Vertrauensliste angeben möchten, die während der Überprüfung anstelle der Systemvertrauensliste verwendet wird, ziehen Sie das folgende Beispiel in Betracht:

SslClientAuthenticationOptions clientOptions = new();

clientOptions.CertificateChainPolicy = new X509ChainPolicy()
{
    TrustMode = X509ChainTrustMode.CustomRootTrust,
    CustomTrustStore =
    {
        customIssuerCert
    }
};

Clients, die mit der vorherigen Richtlinie konfiguriert sind, akzeptieren nur Zertifikate, die vertrauenswürdig sind.customIssuerCert

Bestimmte Überprüfungsfehler ignorieren

Erwägen Sie ein IoT-Gerät ohne dauerhafte Uhr. Nach dem Einschalten würde sich die Uhr des Geräts viele Jahre in die Vergangenheit zurücksetzen und daher würden alle Zertifikate als "noch nicht gültig" betrachtet. Beachten Sie den folgenden Code, der eine Überprüfungsrückrufimplementierung anzeigt, die Gültigkeitsdauerverletzungen ignoriert.

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;
}

Anheften von Zertifikaten

Eine weitere Situation, in der eine benutzerdefinierte Zertifikatüberprüfung erforderlich ist, besteht darin, dass Clients erwarten, dass Server ein bestimmtes Zertifikat oder ein Zertifikat aus einer kleinen Gruppe von bekannten Zertifikaten verwenden. Diese Vorgehensweise wird als Zertifikatheftung bezeichnet. Der folgende Codeausschnitt zeigt einen Validierungsrückruf, der überprüft, ob der Server ein Zertifikat mit einem bestimmten bekannten öffentlichen Schlüssel vorlegt.

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);
}

Überlegungen zur Clientzertifikatüberprüfung

Serveranwendungen müssen beim Anfordern und Überprüfen von Clientzertifikaten vorsichtig sein. Zertifikate können die Erweiterung AIA (Authority Information Access) enthalten, die angibt, wo das Ausstellerzertifikat heruntergeladen werden kann. Der Server kann daher versuchen, das Ausstellerzertifikat vom externen Server herunterzuladen, wenn das X509Chain Clientzertifikat erstellt wird. Ebenso müssen Server möglicherweise externe Server kontaktieren, um sicherzustellen, dass das Clientzertifikat nicht widerrufen wurde.

Die Notwendigkeit, externe Server zu kontaktieren, wenn die X509Chain Anwendung erstellt und überprüft wird, kann die Anwendung anfällig für Denial-of-Service-Angriffe machen, falls die externen Server langsam reagieren. Daher müssen Serveranwendungen das Verhalten für die X509Chain-Erstellung mithilfe von CertificateChainPolicy konfigurieren.