Un sistema en el que estoy trabajando acepta como entrada un número de cuenta de cliente y necesita generar un token basado en él. No se nos permite almacenar el texto simple del número de cuenta, por lo que el objetivo del token es el siguiente:
- No se puede revertir en el número de cuenta.
- Puede utilizarse para buscar e identificar de forma exclusiva un registro de metadatos de cuenta en nuestra base de datos.
Los números de cuenta se parecen a los números de tarjetas de crédito. Son cadenas numéricas largas de 16 dígitos; Los primeros 4 caracteres son constantes; El último carácter es un dígito de control computable. Esto significa que el tamaño real del conjunto de entrada es una cadena numérica de 11 caracteres: 99,999,999,999 posibles permutaciones.
He pensado en los métodos a continuación. Supongamos que hash significa un hash seguro suficientemente lento, como PBKDF2 de alta iteración, bcrypt o argon2 y encrypt significa AES256.
1. Hash simple
hash(account_num)
Aunque es simple, este enfoque es fácil de revertir a través de la fuerza bruta y es vulnerable a las tablas del arco iris.
2. Hash salado por cuenta
hash(salt + account_num)
Este enfoque corrige la vulnerabilidad a las tablas de arco iris, sin embargo, debido al tamaño limitado del conjunto de entrada, todavía es fácil de revertir a través de la fuerza bruta.
3. Hash salado por usuario cifrado con Global Pepper
encrypt(hash( salt + account_num ), pepper)
Esto se basa en mecanismo de almacenamiento de contraseñas de Dropbox . La inversión a través de la fuerza bruta requiere que se filtren los blobs cifrados y la clave de cifrado. Sin embargo, dado que cifrar el mismo valor dos veces con la misma clave produce diferentes blobs de salida, esto rompe la capacidad de seleccionar una cuenta de la base de datos por número de cuenta.
4. Enfoque híbrido
- Almacene los últimos 4 dígitos del número de cuenta en texto sin formato.
- Almacena el número de cuenta completo como un hash salado encriptado con pimienta.
- Use AWS KMS para el cifrado hash para reducir las probabilidades de perder una clave.
Lo que esto logra:
- Podemos buscar cuentas utilizando los últimos 4 dígitos del número de cuenta. Basándose en la comprobación de unos pocos miles de números de cuenta, esta selección devolverá entre 1 y 3 cuentas posibles.
- Iterar sobre cada una de las posibles coincidencias de cuenta ...
- Descifre el hash del número de cuenta para la cuenta.
- Compare el hash descifrado con el número de cuenta de entrada.
- Detenga la iteración tan pronto como encontremos un hash que coincida (use esta fila de la cuenta) o se quede sin cuentas (cree una nueva fila de la cuenta).
Mi pregunta: ¿Tiene sentido el enfoque 4 en realidad? Por la seguridad adicional que proporciona, ¿es demasiado complicado? ¿Tiene defectos que no he pensado? Más que nada, ¿hay una manera más sencilla de resolver este problema?