Udostępnij za pośrednictwem


Najlepsze rozwiązania dotyczące protokołu TLS/SSL

TLS (Transport Layer Security) to protokół kryptograficzny przeznaczony do zabezpieczania komunikacji między dwoma komputerami za pośrednictwem Internetu. Protokół TLS jest uwidaczniony na platformie .NET za pośrednictwem SslStream klasy .

W tym artykule przedstawiono najlepsze rozwiązania dotyczące konfigurowania bezpiecznej komunikacji między klientem a serwerem i przyjęto założenie użycia platformy .NET. Aby uzyskać najlepsze rozwiązania dotyczące programu .NET Framework, zobacz Transport Layer Security (TLS) best practices with the .NET Framework (Transport Layer Security, Transport Layer Security) best practices with the .NET Framework (Najlepsze rozwiązania dotyczące protokołu Transport Layer Security (TLS).

Wybierz wersję protokołu TLS

Chociaż można określić wersję protokołu TLS, która ma być używana za pośrednictwem EnabledSslProtocols właściwości, zaleca się odroczenie ustawień systemu operacyjnego przy użyciu None wartości (jest to wartość domyślna).

Odroczenie decyzji systemu operacyjnego automatycznie używa najnowszej dostępnej wersji protokołu TLS i umożliwia aplikacji pobieranie zmian po uaktualnieniu systemu operacyjnego. System operacyjny może również uniemożliwić korzystanie z wersji protokołu TLS, które nie są już uważane za bezpieczne.

Wybieranie zestawów szyfrowania

SslStream umożliwia użytkownikom określenie, które zestawy szyfrowania mogą być negocjowane przez uzgadnianie protokołu TLS za pośrednictwem CipherSuitesPolicy klasy . Podobnie jak w przypadku wersji protokołu TLS zaleca się umożliwienie systemowi operacyjnemu decydowania, które są najlepszymi zestawami szyfrowania do negocjowania, a zatem zaleca się unikanie korzystania z programu CipherSuitesPolicy.

Uwaga

CipherSuitesPolicy program nie jest obsługiwany w systemie Windows i próby utworzenia wystąpienia spowoduje NotSupportedException zgłoszenie.

Określanie certyfikatu serwera

W przypadku uwierzytelniania jako serwera SslStream wymagane X509Certificate2 jest wystąpienie. Zaleca się zawsze używanie X509Certificate2 wystąpienia, które zawiera również klucz prywatny.

Istnieje wiele sposobów przekazywania certyfikatu serwera do programu SslStream:

Zalecaną metodą jest użycie SslServerAuthenticationOptions.ServerCertificateContext właściwości . Gdy certyfikat jest uzyskiwany na jeden z dwóch pozostałych sposobów, SslStreamCertificateContext wystąpienie jest tworzone wewnętrznie przez implementację SslStream . Tworzenie obiektu SslStreamCertificateContext obejmuje utworzenie obiektu X509Chain , który jest operacją intensywnie korzystającą z procesora CPU. Wydajniejsze jest utworzenie SslStreamCertificateContext raz i ponowne użycie go dla wielu SslStream wystąpień.

Ponowne użycie SslStreamCertificateContext wystąpień umożliwia również dodatkowe funkcje, takie jak wznowienie sesji TLS na serwerach z systemem Linux.

Walidacja niestandardowa X509Certificate

Istnieją pewne scenariusze, w których domyślna procedura weryfikacji certyfikatu nie jest odpowiednia i wymagana jest pewna niestandardowa logika walidacji. Części logiki walidacji można dostosować, określając SslClientAuthenticationOptions.CertificateChainPolicy lub SslServerAuthenticationOptions.CertificateChainPolicy. Alternatywnie można udostępnić całkowicie niestandardową logikę za pośrednictwem <właściwości System.Net.Security.SslClientAuthenticationOptions.RemoteCertificateValidationCallback> . Aby uzyskać więcej informacji, zobacz Niestandardowe zaufanie certyfikatów.

Zaufanie niestandardowego certyfikatu

W przypadku napotkania certyfikatu, który nie został wystawiony przez żadne z urzędów certyfikacji zaufanych przez maszynę (w tym certyfikaty z podpisem własnym), domyślna procedura weryfikacji certyfikatu zakończy się niepowodzeniem. Jednym z możliwych sposobów rozwiązania tego problemu jest dodanie niezbędnych certyfikatów wystawcy do zaufanego magazynu maszyny. Może to jednak mieć wpływ na inne aplikacje w systemie i nie zawsze jest możliwe.

Alternatywnym rozwiązaniem jest określenie niestandardowych zaufanych certyfikatów głównych za pośrednictwem elementu X509ChainPolicy. Aby określić niestandardową listę zaufania, która będzie używana zamiast listy zaufania systemu podczas walidacji, rozważ następujący przykład:

SslClientAuthenticationOptions clientOptions = new();

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

Klienci skonfigurowani z poprzednimi zasadami akceptują tylko certyfikaty zaufane przez customIssuerCertusługę .

Ignoruj określone błędy walidacji

Rozważ urządzenie IoT bez trwałego zegara. Po włączeniu zasilania zegar urządzenia rozpocznie się wiele lat w przeszłości i dlatego wszystkie certyfikaty zostaną uznane za "jeszcze nieprawidłowe". Rozważ poniższy kod, który pokazuje implementację wywołania zwrotnego weryfikacji ignorując naruszenia okresu ważności.

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

Przypinanie certyfikatu

Inną sytuacją, w której konieczna jest niestandardowa weryfikacja certyfikatu, jest sytuacja, w której klienci oczekują, że serwery będą używać określonego certyfikatu lub certyfikatu z małego zestawu znanych certyfikatów. Ta praktyka jest znana jako przypinanie certyfikatu. Poniższy fragment kodu przedstawia wywołanie zwrotne weryfikacji, które sprawdza, czy serwer przedstawia certyfikat z określonym znanym kluczem publicznym.

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

Zagadnienia dotyczące weryfikacji certyfikatu klienta

Aplikacje serwera muszą być ostrożne podczas wymagania i weryfikowania certyfikatów klienta. Certyfikaty mogą zawierać rozszerzenie AIA (Authority Information Access), które określa, gdzie można pobrać certyfikat wystawcy. Serwer może zatem podjąć próbę pobrania certyfikatu wystawcy z serwera zewnętrznego podczas kompilowania X509Chain certyfikatu klienta. Podobnie serwery mogą wymagać kontaktu z serwerami zewnętrznymi, aby upewnić się, że certyfikat klienta nie został odwołany.

Konieczność kontaktowania się z serwerami zewnętrznymi podczas kompilowania i weryfikowania X509Chain może spowodować ujawnienie aplikacji ataków typu "odmowa usługi", jeśli serwery zewnętrzne będą reagować wolno. W związku z tym aplikacje serwerowe powinny skonfigurować X509Chain zachowanie budynku przy użyciu elementu CertificateChainPolicy.