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.
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étodoCreateProtector
criará um objetoIDataProtector
exclusivamente vinculado ao objeto que oIDataProtectionProvider
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 objetosIDataProtectionProvider
equivalentes com parâmetros de finalidade equivalentes.Para um determinado objeto
IDataProtector
, uma chamada paraUnprotect(protectedData)
retornará ounprotectedData
original se e somente seprotectedData := Protect(unprotectedData)
for para um objetoIDataProtector
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.