Cadenas de propósito en ASP.NET Core
Los componentes que consumen IDataProtectionProvider
deben pasar un parámetro de propósito único al métodoCreateProtector
. El parámetro de propósitos es inherente a la seguridad del sistema de protección de datos, ya que proporciona aislamiento entre consumidores criptográficos, incluso si las claves criptográficas raíz son las mismas.
Cuando un consumidor especifica un propósito, la cadena de propósito se usa junto con las claves criptográficas raíz para derivar subclaves criptográficas únicas para ese consumidor. Esto aísla al consumidor de todos los demás consumidores criptográficos de la aplicación: ningún otro componente puede leer sus cargas y no puede leer las cargas de ningún otro componente. Este aislamiento también representa categorías completas de ataque inviables contra el componente.
En el diagrama anterior, IDataProtector
las instancias A y B no pueden leer las cargas útiles de los demás, solo las suyas.
La cadena de propósito no tiene que ser secreta. Simplemente debe ser único en el sentido de que ningún otro componente bien comportado nunca proporcionará la misma cadena de propósito.
Sugerencia
El uso del espacio de nombres y el nombre de tipo del componente que consume las API de protección de datos es una buena regla general, como en la práctica, esta información nunca entrará en conflicto.
Un componente creado por Contoso que es responsable de la creación de tokens de portador podría usar Contoso.Security.BearerToken como cadena de propósito. O bien, incluso mejor, podría usar Contoso.Security.BearerToken.v1 como cadena de propósito. Anexar el número de versión permite que una versión futura use Contoso.Security.BearerToken.v2 como su propósito, y las distintas versiones se aislarían completamente entre sí en lo que respecta a las cargas.
Dado que el parámetro de propósito para CreateProtector
es una matriz de cadenas, el anterior podría haberse especificado en su lugar como [ "Contoso.Security.BearerToken", "v1" ]
. Esto permite establecer una jerarquía de propósitos y abre la posibilidad de escenarios multiinquilino con el sistema de protección de datos.
Advertencia
Los componentes no deben permitir que la entrada del usuario que no sea de confianza sea el único origen de entrada para la cadena de propósitos.
Por ejemplo, considere un componente Contoso.Messaging.SecureMessage que es responsable de almacenar mensajes seguros. Si el componente de mensajería segura llamara aCreateProtector([ username ])
, un usuario malintencionado podría crear una cuenta con el nombre de usuario "Contoso.Security.BearerToken" en un intento de obtener el componente para llamar a CreateProtector([ "Contoso.Security.BearerToken" ])
, lo que provocaba accidentalmente que el sistema de mensajería seguro acuñara cargas que se podían percibir como tokens de autenticación.
Una cadena de propósitos mejor para el componente de mensajería sería CreateProtector([ "Contoso.Messaging.SecureMessage", $"User: {username}" ])
, que proporciona un aislamiento adecuado.
El aislamiento proporcionado por los comportamientos y de IDataProtectionProvider
, IDataProtector
, y los propósitos son los siguientes:
Para un objeto determinado
IDataProtectionProvider
, el métodoCreateProtector
creará unIDataProtector
objeto vinculado de forma única al objetoIDataProtectionProvider
que lo creó y el parámetro de propósito que se pasó al método .El parámetro propósito no debe ser null. (Si se especifica el propósito como una matriz, esto significa que la matriz no debe tener una longitud cero y todos los elementos de la matriz deben ser distintos de null). Técnicamente se permite un propósito de cadena vacío, pero no se recomienda.
Dos argumentos de propósito son equivalentes si y solo si contienen las mismas cadenas (mediante un comparador ordinal) en el mismo orden. Un único argumento de propósito es equivalente a la matriz de propósitos de un solo elemento correspondiente.
Dos objetos
IDataProtector
son equivalentes si y solo si se crean a partir de objetos equivalentesIDataProtectionProvider
con parámetros de propósito equivalentes.Para un objeto determinado
IDataProtector
, una llamada aUnprotect(protectedData)
devolverá el originalunprotectedData
si y solo siprotectedData := Protect(unprotectedData)
es para un objeto equivalenteIDataProtector
.
Nota:
No estamos considerando el caso en el que algún componente elige intencionadamente una cadena de propósito que se sabe que entra en conflicto con otro componente. Este componente se consideraría esencialmente malintencionado y este sistema no pretende proporcionar garantías de seguridad en caso de que el código malintencionado ya se esté ejecutando dentro del proceso de trabajo.