Cadeias de caracteres de finalidade no ASP.NET Core

Os componentes que consomem IDataProtectionProvider devem passar um parâmetro de finalidade exclusivo para o método CreateProtector. O parâmetro de finalidade é inerente à segurança do sistema de proteção de dados, pois fornece isolamento entre consumidores criptográficos, mesmo que as chaves criptográficas raiz sejam as mesmas.

Quando um consumidor especifica uma finalidade, a cadeia de caracteres de finalidade é usada junto com as chaves criptográficas raiz para derivar subchaves criptográficas exclusivas para esse consumidor. Isso isola o consumidor de todos os outros consumidores criptográficos no aplicativo: nenhum outro componente pode ler suas cargas e não pode ler as cargas de nenhum outro componente. Esse isolamento também renderiza categorias inteiras inviáveis de ataque contra o componente.

Purpose Diagram Example

No diagrama acima, IDataProtector as instâncias A e B não podem ler as cargas umas das outras, apenas as próprias.

A cadeia de caracteres de finalidade não precisa ser secreta. Ele deve ser simplesmente exclusivo no sentido de que nenhum outro componente bem comportado jamais fornecerá a mesma cadeia de caracteres de finalidade.

Dica

Usar o namespace e o nome do tipo do componente que consome as APIs de proteção de dados é uma boa regra geral, pois, na prática, essas informações nunca entrarão em conflito.

Um componente de autoria da Contoso responsável por criar tokens de portador pode usar Contoso.Security.BearerToken como sua cadeia de caracteres de finalidade. Ou, ainda melhor, pode usar Contoso.Security.BearerToken.v1 como sua cadeia de caracteres de finalidade. Acrescentar o número de versão permite que uma versão futura use Contoso.Security.BearerToken.v2 como sua finalidade, e as diferentes versões seriam completamente isoladas umas das outras no que diz respeito às cargas.

Como o parâmetro purposes para CreateProtector é uma matriz de cadeia de caracteres, o exposto acima poderia ter sido especificado como [ "Contoso.Security.BearerToken", "v1" ]. Isso permite estabelecer uma hierarquia de finalidades e abre a possibilidade de cenários de várias locações com o sistema de proteção de dados.

Aviso

Os componentes não devem permitir que a entrada de usuário não confiável seja a única fonte de entrada para a cadeia de finalidades.

Por exemplo, considere um componente Contoso.Messaging.SecureMessage responsável por armazenar mensagens seguras. Se o componente de mensagens seguras chamasse CreateProtector([ username ]), um usuário mal-intencionado poderia criar uma conta com o nome de usuário "Contoso.Security.BearerToken" na tentativa de fazer com que o componente chamasse CreateProtector([ "Contoso.Security.BearerToken" ]), fazendo com que, inadvertidamente, o sistema de mensagens segura criasse cargas que poderiam ser percebidas como tokens de autenticação.

Uma cadeia de finalidades melhor para o componente de mensagens seria CreateProtector([ "Contoso.Messaging.SecureMessage", $"User: {username}" ]), que fornece isolamento adequado.

O isolamento fornecido pelos comportamentos de IDataProtectionProvider, IDataProtector e as finalidade são conforme descrito a seguir:

  • Para um determinado objeto IDataProtectionProvider, o método CreateProtector criará um objeto IDataProtector exclusivamente vinculado ao objeto que o IDataProtectionProvider criou e ao parâmetro finalidades que foi passado para o método .

  • Esse parâmetro não deve ser nulo. (Se as finalidades forem especificadas como uma matriz, isso significa que a matriz não deve ter tamanho zero e todos os elementos da matriz devem ser não nulos.) Uma finalidade de cadeia de caracteres vazia é tecnicamente permitida, mas é desencorajada.

  • Dois argumentos de finalidade são equivalentes se e somente se contiverem as mesmas cadeias de caracteres (usando um comparador ordinal) na mesma ordem. Um único argumento de finalidade é equivalente à matriz de finalidades de elemento único correspondente.

  • Dois objetos IDataProtector serão equivalentes se e somente se forem criados a partir de objetos IDataProtectionProvider equivalentes com parâmetros de finalidade equivalentes.

  • Para um determinado objeto IDataProtector, uma chamada para Unprotect(protectedData) retornará o unprotectedData original se e somente se protectedData := Protect(unprotectedData) for para um objeto IDataProtector equivalente.

Observação

Não estamos considerando o caso em que algum componente escolhe intencionalmente uma cadeia de caracteres de finalidade que é conhecida por entrar em conflito com outro componente. Esse componente seria essencialmente considerado mal-intencionado, e esse sistema não se destina a fornecer garantias de segurança caso o código mal-intencionado já esteja em execução dentro do processo de trabalho.