Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O TLS (Transport Layer Security) é um protocolo criptográfico projetado para proteger a comunicação entre dois computadores pela Internet. O protocolo TLS é exposto no .NET por meio da SslStream classe.
Este artigo apresenta as práticas recomendadas para configurar a comunicação segura entre o cliente e o servidor e pressupõe o uso do .NET. Para obter as práticas recomendadas com o .NET Framework, consulte as práticas recomendadas de TLS (Transport Layer Security) com o .NET Framework.
Selecionar a versão do TLS
Embora seja possível especificar a versão do protocolo TLS a ser usada por meio da EnabledSslProtocols propriedade, é recomendável adiar para as configurações do sistema operacional usando None o valor (esse é o padrão).
Delegar a decisão ao sistema operacional usa automaticamente a versão mais recente do TLS disponível e permite que o aplicativo aplique as alterações após as atualizações do sistema operacional. O sistema operacional também pode impedir o uso de versões TLS que não são mais consideradas seguras.
Selecionar conjuntos de criptografia
SslStream permite que os usuários especifiquem quais conjuntos de criptografia podem ser negociados pelo handshake do TLS por meio da CipherSuitesPolicy classe. Assim como acontece com as versões do TLS, é recomendável permitir que o sistema operacional decida quais são os melhores pacotes de criptografia com os quais negociar e, portanto, é recomendável evitar o uso CipherSuitesPolicy.
Observação
O CipherSuitesPolicy não tem suporte no Windows e as tentativas de instanciá-lo farão com que NotSupportedException seja lançado.
Especificar um certificado local
Ao autenticar como um servidor, SslStream sempre requer um certificado. Ao autenticar como um cliente, você também fornecerá um certificado se o servidor solicitar um para o TLS mútuo (mTLS). Em ambas as funções, o certificado deve ser uma X509Certificate2 instância que contenha a chave privada.
Versões de .NET recentes lidam com o servidor e os lados do cliente simetricamente, portanto, as diretrizes a seguir se aplicam se o aplicativo se autentica como um servidor, um cliente ou ambos.
Você pode fornecer o certificado para SslStream de várias formas.
Quando você se autentica como um servidor:
- Defina a SslServerAuthenticationOptions.ServerCertificate propriedade ou passe o certificado para SslStream.AuthenticateAsServerAsync.
- Retorne o certificado do SslServerAuthenticationOptions.ServerCertificateSelectionCallback retorno de chamada.
- Defina um SslStreamCertificateContext na propriedade SslServerAuthenticationOptions.ServerCertificateContext.
Quando você se autentica como um cliente:
- Adicione o certificado à SslClientAuthenticationOptions.ClientCertificates coleção ou passe uma coleção que o contenha para SslStream.AuthenticateAsClientAsync.
- Retorne o certificado a partir do callback SslClientAuthenticationOptions.LocalCertificateSelectionCallback.
- Defina um SslStreamCertificateContext na propriedade SslClientAuthenticationOptions.ClientCertificateContext.
Observação
A ClientCertificateContext propriedade está disponível a partir de .NET 8.
Para obter um melhor desempenho, use a propriedade de contexto do certificado (ServerCertificateContext ou ClientCertificateContext). Quando você fornece o certificado de uma das outras maneiras, SslStream cria um SslStreamCertificateContext internamente. A criação do contexto cria uma X509Chainoperação com uso intensivo de CPU, portanto, é mais eficiente criar o contexto uma vez e reutilizá-lo em várias SslStream instâncias.
A reutilização de uma SslStreamCertificateContext instância também permite recursos extras, como a retomada da sessão do TLS em servidores Linux.
Enviar certificados intermediários para o par remoto
Quando uma autoridade de certificação intermediária emite o certificado local, o par pode não ser capaz de criar a cadeia de certificados completa, a menos que o handshake inclua os certificados intermediários. Para enviar esses certificados intermediários, crie um SslStreamCertificateContext com o método Create e passe os certificados intermediários no parâmetro additionalCertificates:
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;
O contexto funciona da mesma maneira para ambas as funções. No lado do cliente, o contexto do certificado é a maneira recomendada de enviar intermediários, pois a alternativa , adicionando os intermediários ao repositório de certificados do computador ou do usuário, afeta todos os aplicativos no sistema.
Validação personalizada X509Certificate
Há certos cenários em que o procedimento de validação de certificado padrão não é adequado e alguma lógica de validação personalizada é necessária. Partes da lógica de validação podem ser personalizadas especificando SslClientAuthenticationOptions.CertificateChainPolicy ou SslServerAuthenticationOptions.CertificateChainPolicy. Como alternativa, a lógica completamente personalizada pode ser fornecida por meio da <propriedade System.Net.Security.SslClientAuthenticationOptions.RemoteCertificateValidationCallback> . Para obter mais informações, consulte confiança de certificado personalizado.
Confiança de certificado personalizada
Ao encontrar um certificado que não foi emitido por nenhuma das autoridades de certificação confiáveis pelo computador (incluindo certificados autoassinados), o procedimento de validação de certificado padrão falhará. Uma maneira possível de resolver isso é adicionar os certificados do emissor necessários ao repositório confiável do computador. Isso, no entanto, pode afetar outros aplicativos no sistema e nem sempre é possível.
A solução alternativa é especificar certificados raiz confiáveis personalizados por meio de um X509ChainPolicy. Para especificar uma lista de confiança personalizada que será usada em vez da lista de confiança do sistema durante a validação, considere o seguinte exemplo:
SslClientAuthenticationOptions clientOptions = new();
clientOptions.CertificateChainPolicy = new X509ChainPolicy()
{
TrustMode = X509ChainTrustMode.CustomRootTrust,
CustomTrustStore =
{
customIssuerCert
}
};
Os clientes configurados com a política anterior só aceitariam certificados confiáveis por customIssuerCert.
Ignorar erros de validação específicos
Considere um dispositivo IoT sem um relógio persistente. Depois de ligado, o relógio do dispositivo começaria muitos anos no passado e, portanto, todos os certificados seriam considerados "ainda não válidos". Considere o seguinte código que mostra uma implementação de callback de validação que ignora violações do período de validade.
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;
}
Anexação de certificado
Outra situação em que a validação de certificado personalizado é necessária é quando os clientes esperam que os servidores usem um certificado específico ou um certificado de um pequeno conjunto de certificados conhecidos. Essa prática é conhecida como anexação de certificado. O snippet de código a seguir mostra um retorno de chamada de validação que verifica se o servidor apresenta um certificado com uma chave pública conhecida específica.
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);
}
Considerações sobre a validação do certificado do cliente
Os aplicativos de servidor precisam ter cuidado ao exigir e validar certificados de cliente. Os certificados podem conter a extensão AIA (Acesso às Informações da Autoridade), que especifica onde o certificado do emissor pode ser baixado. Portanto, ao compilar o certificado do cliente, o servidor pode tentar baixar o certificado do emissor a partir de um servidor externo. Da mesma forma, os servidores podem precisar entrar em contato com servidores externos para garantir que o certificado do cliente não tenha sido revogado.
A necessidade de contatar servidores externos ao compilar e validar o X509Chain aplicativo poderá expor o aplicativo a ataques de negação de serviço se os servidores externos demorarem a responder. Portanto, os aplicativos de servidor devem configurar o comportamento de compilação de X509Chain usando o CertificateChainPolicy.
Observação
A partir do .NET 11, SslStream desabilita os downloads de certificado do AIA por padrão ao validar certificados do cliente como um servidor. Se nenhum certificado personalizado CertificateChainPolicy for fornecido, o servidor não tentará buscar certificados intermediários ausentes por meio do AIA. Para obter mais informações, consulte Downloads de certificado AIA do lado do servidor SslStream desabilitados por padrão.