Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
TLS (транспортный уровень безопасности) — это криптографический протокол, предназначенный для защиты связи между двумя компьютерами через Интернет. Протокол TLS предоставляется в .NET через SslStream класс.
В этой статье представлены рекомендации по настройке безопасного взаимодействия между клиентом и сервером и предполагается использование .NET. Рекомендации по использованию .NET Framework см. в рекомендациях по протоколу TLS с помощью .NET Framework.
Выбор версии TLS
Хотя можно указать версию протокола TLS для использования с помощью EnabledSslProtocols свойства, рекомендуется отложить параметры операционной системы с помощью None значения (это значение по умолчанию).
Отложение решения на ОС автоматически использует последнюю версию TLS и позволяет приложению выполнять изменения после обновления ОС. Операционная система также может предотвратить использование версий TLS, которые больше не считаются безопасными.
Выбор наборов шифров
SslStream
позволяет пользователям указать, какие наборы шифров можно согласовывать с помощью подтверждения TLS через CipherSuitesPolicy класс. Как и в случае с версиями TLS, рекомендуется разрешить ОС решить, с какими из лучших наборов шифров можно вести переговоры, и поэтому рекомендуется избежать использования CipherSuitesPolicy.
Замечание
CipherSuitesPolicy не поддерживается в Windows, и попытка создать его экземпляр приведет к возникновению NotSupportedException.
Указание сертификата сервера
При проверке подлинности в качестве сервера SslStream требуется экземпляра X509Certificate2. Рекомендуется всегда использовать экземпляр X509Certificate2, который также содержит закрытый ключ.
Существует несколько способов, которым можно передать SslStreamсертификат сервера:
- Непосредственно в качестве параметра для SslStream.AuthenticateAsServerAsync или через свойство SslServerAuthenticationOptions.ServerCertificate
- Из обратного вызова выбора в SslServerAuthenticationOptions.ServerCertificateSelectionCallback свойстве
- Путем передачи SslStreamCertificateContext в свойстве SslServerAuthenticationOptions.ServerCertificateContext
Рекомендуемый подход — использовать SslServerAuthenticationOptions.ServerCertificateContext свойство. При получении сертификата одним из двух других способов SslStreamCertificateContext экземпляр создается внутри SslStream реализации. Создание SslStreamCertificateContext включает построение X509Chain, что является ресурсозатратной для ЦП операцией. Более эффективно создать SslStreamCertificateContext один раз и повторно использовать его для нескольких SslStream экземпляров.
Повторное использование экземпляров также позволяет использовать дополнительные функции, например, возобновление SslStreamCertificateContextсеансa TLS на серверах Linux.
Настраиваемая X509Certificate
проверка
Существуют определенные сценарии, в которых процедура проверки сертификатов по умолчанию не является достаточной, и требуется определенная пользовательская логика проверки. Части логики проверки можно настроить, указав SslClientAuthenticationOptions.CertificateChainPolicy или SslServerAuthenticationOptions.CertificateChainPolicy. Кроме того, полностью настраиваемую логику можно предоставить с помощью <свойства System.Net.Security.SslClientAuthenticationOptions.RemoteCertificateValidationCallback> . Дополнительные сведения см. в разделе "Доверие пользовательских сертификатов".
Доверие пользовательских сертификатов
При обнаружении сертификата, который не был выдан ни одним из центров сертификации, доверенных системой, включая самозаверяющие сертификаты, процедура проверки сертификатов по умолчанию завершится ошибкой. Одним из возможных способов устранения этой проблемы является добавление необходимых сертификатов издателя в доверенное хранилище компьютера. Однако это может повлиять на другие приложения в системе и не всегда возможно.
Альтернативное решение заключается в указании пользовательских доверенных корневых сертификатов с помощью X509ChainPolicy. Чтобы указать настраиваемый список доверия, который будет использоваться вместо списка доверия системы во время проверки, рассмотрим следующий пример:
SslClientAuthenticationOptions clientOptions = new();
clientOptions.CertificateChainPolicy = new X509ChainPolicy()
{
TrustMode = X509ChainTrustMode.CustomRootTrust,
CustomTrustStore =
{
customIssuerCert
}
};
Клиенты, настроенные с предыдущей политикой, будут принимать только доверенные customIssuerCert
сертификаты.
Игнорировать определенные ошибки проверки
Рассмотрим устройство Интернета вещей без постоянных часов. После включения часы устройства будут устанавливаться на много лет назад, и, следовательно, все сертификаты будут считаться "еще не действительными". Рассмотрим следующий код, показывающий реализацию обратного вызова проверки, игнорирующую нарушения срока действия.
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;
}
Привязка к сертификату
Другая ситуация, когда требуется проверка пользовательских сертификатов, заключается в том, что клиенты ожидают, что серверы будут использовать определенный сертификат или сертификат из небольшого набора известных сертификатов. Эта практика называется закреплением сертификатов. В следующем фрагменте кода показан обратный вызов проверки, который проверяет, что сервер представляет сертификат с определенным открытым ключом.
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);
}
Рекомендации по проверке сертификата клиента
Серверные приложения должны быть осторожны при необходимости и проверке сертификатов клиента. Сертификаты могут содержать расширение AIA (доступ к данным центра), указывающее, где можно скачать сертификат издателя. Поэтому сервер может попытаться скачать сертификат издателя с внешнего сервера при создании X509Chain сертификата клиента. Аналогичным образом, серверы могут обратиться к внешним серверам, чтобы убедиться, что сертификат клиента не был отозван.
Необходимость связаться с внешними серверами при создании и проверке X509Chain приложения может привести к атакам типа "отказ в обслуживании", если внешние серверы медленно реагируют. Поэтому серверные приложения должны настроить поведение сборки X509Chain с помощью CertificateChainPolicy.