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 de servidor
Ao autenticar como um servidor, SslStream requer uma X509Certificate2 instância. É recomendável sempre usar uma X509Certificate2 instância que também contenha a chave privada.
Há várias maneiras pelas quais um certificado de servidor pode ser passado para SslStream:
- Diretamente como um parâmetro, para SslStream.AuthenticateAsServerAsync, ou por meio da propriedade SslServerAuthenticationOptions.ServerCertificate
- Via retorno de chamada de seleção na propriedade SslServerAuthenticationOptions.ServerCertificateSelectionCallback
- Passando um SslStreamCertificateContext na propriedade SslServerAuthenticationOptions.ServerCertificateContext
A abordagem recomendada é usar a SslServerAuthenticationOptions.ServerCertificateContext propriedade. Quando o certificado é obtido por uma das outras duas maneiras, uma SslStreamCertificateContext instância é criada internamente pela SslStream implementação. Criar um SslStreamCertificateContext envolve criar uma X509Chain, que é uma operação intensiva para a CPU. É mais eficiente criar um único SslStreamCertificateContext e reutilizá-lo em várias instâncias de SslStream.
A reutilização de SslStreamCertificateContext instâncias também permite recursos adicionais, como a retomada da sessão TLS em servidores Linux.
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;
}
Fixaçã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.