hash cryptography credit-card

hash - La mejor forma de evitar el uso duplicado de tarjetas de crédito



cryptography credit-card (15)

Tenemos un sistema en el que queremos evitar que se registre el mismo número de tarjeta de crédito para dos cuentas diferentes. Como no almacenamos internamente el número de la tarjeta de crédito, solo los últimos cuatro dígitos y la fecha de vencimiento, no podemos simplemente comparar los números de tarjetas de crédito y las fechas de vencimiento.

Nuestra idea actual es almacenar un hash (SHA-1) en nuestro sistema de la información de la tarjeta de crédito cuando se registra la tarjeta, y comparar hashes para determinar si una tarjeta se ha utilizado anteriormente.

Por lo general, una sal se usa para evitar ataques de diccionario. Supongo que somos vulnerables en este caso, por lo que probablemente deberíamos almacenar una sal junto con el hash.

¿Ustedes ven algún defecto en este método? ¿Es esta una forma estándar de resolver este problema?


Comparar hashes es una buena solución. Sin embargo, asegúrese de no saldar todos los números de tarjeta de crédito con la misma sal constante. Use una sal diferente (como la fecha de caducidad) en cada tarjeta. Esto debería hacerte bastante impermeable a los ataques de diccionario.

De este artículo de Coding Horror :

Agregue una sal aleatoria larga y única a cada contraseña que almacene. El punto de una sal (o nonce, si lo prefiere) es hacer que cada contraseña sea única y lo suficientemente larga como para que los ataques de fuerza bruta sean una pérdida de tiempo. Por lo tanto, la contraseña del usuario, en lugar de almacenarse como el hash de "myspace1", termina siendo almacenada como el hash de 128 caracteres de cadena unicode aleatoria + "myspace1". Ahora eres completamente inmune al ataque de mesa arcoiris.


Creo que una buena solución, como se insinuó anteriormente, sería almacenar un valor hash de, digamos, Número de tarjeta, Fecha de caducidad y nombre. De esa forma, aún puedes hacer comparaciones rápidas ...


Hagamos un poco de matemáticas: los números de las tarjetas de crédito tienen 16 dígitos. Los primeros siete dígitos son ''industria importante'' y números de emisor, y el último dígito es la suma de comprobación luhn. Eso deja 8 dígitos ''gratis'', para un total de 100,000,000 números de cuenta, multiplicado por el número de números potenciales de emisor (que no es probable que sea muy alto). Hay implementaciones que pueden hacer millones de hash por segundo en el hardware de todos los días, así que no importa qué salazón se haga, esto no será un gran problema para la fuerza bruta.

Por pura coincidencia, cuando busco algo que proporcione puntos de referencia de algoritmos hash, encontré este artículo sobre el almacenamiento de hashes de tarjetas de crédito , que dice:

Almacenar tarjetas de crédito usando un solo paso simple de un algoritmo hash, incluso cuando está salado, es tonto. Simplemente es demasiado fácil obligar a la fuerza bruta a los números de la tarjeta de crédito si los hashes están en peligro.

...

Cuando se usa el número de la tarjeta de crédito hash, el hash debe diseñarse cuidadosamente para proteger contra el forzamiento bruto utilizando las funciones hash criptográficas más potentes disponibles, los valores de sal grandes y las iteraciones múltiples.

El artículo completo merece una lectura a fondo. Desafortunadamente, el resultado parece ser que cualquier circunstancia que haga que sea ''seguro'' almacenar números de tarjetas de crédito con hash también hará que sea prohibitivamente costoso buscar duplicados.


La gente está pensando en el diseño de esto, creo. Use un hash salado, altamente seguro (por ejemplo, "computacionalmente caro") como sha-256, con una sal única por registro.

Primero debe realizar un control de alta precisión y bajo costo y luego realizar el control definitivo de alto costo solo si se produce un control.

Paso 1:

Busque coincidencias con los últimos 4 dígitos (y posiblemente también la fecha de expiración, aunque hay algunas sutilezas que pueden necesitar ser abordadas).

Paso 2:

Si la comprobación simple golpea, use la sal, obtenga el valor hash, realice la verificación en profundidad.

Los últimos 4 dígitos del cc # son los más únicos (en parte porque también incluyen el dígito de verificación LUHN), por lo que el porcentaje de controles en profundidad que hará que no coincidirán (la tasa de falsos positivos) será muy alta. muy bajo (una fracción de un porcentaje), lo que le ahorra una gran cantidad de gastos generales en comparación con el ingenuo diseño de "compruebe el hash cada vez".


Sí, la comparación de hashes debería funcionar bien en este caso.


SHA1 está roto . Por supuesto, no hay mucha información sobre qué es un buen reemplazo. SHA2?


Sha1 roto no es un problema aquí. Todos los medios rotos son que es posible calcular colisiones (2 conjuntos de datos que tienen el mismo sha1) más fácilmente de lo que cabría esperar. Esto podría ser un problema para aceptar archivos arbitrarios en función de su sha1, pero no tiene relevancia para una aplicación interna de hash.


Si combina los últimos 4 dígitos del número de tarjeta con el nombre del titular de la tarjeta (o solo el apellido) y la fecha de vencimiento, debe tener suficiente información para que el registro sea único. Hashing es bueno para la seguridad, pero ¿no sería necesario almacenar / recuperar la sal para replicar el hash para un chequeo duplicado?


Un hash salado debería funcionar bien. Tener un sistema de sal por usuario debería ser una gran seguridad.


PCI DSS establece que puede almacenar PAN (números de tarjeta de crédito) usando un fuerte hash unidireccional. Ni siquiera requieren que sea salado. Dicho esto, deberías salarlo con un valor único por tarjeta. La fecha de vencimiento es un buen comienzo, pero tal vez demasiado corto. Puede agregar otros datos de la tarjeta, como el emisor. No debe usar el número CVV / de seguridad ya que no tiene permitido almacenarlo. Si utiliza la fecha de caducidad, cuando se le expida una nueva tarjeta al titular de la tarjeta con el mismo número, contará como una tarjeta diferente. Esto podría ser bueno o malo dependiendo de sus requisitos.

Un enfoque para hacer que sus datos sean más seguros es hacer que cada operación sea computacionalmente costosa. Por ejemplo, si md5 dos veces, un atacante tardará más en descifrar los códigos.

Es bastante trivial generar números de tarjeta de crédito válidos y tratar de cobrar por cada posible fecha de vencimiento. Sin embargo, es computacionalmente costoso. Si haces que te resulte más caro crackear tus hashes, entonces no valdría la pena que nadie se moleste; incluso si tuvieran las sales, los hash y el método que usaste.


Casi una buena idea.

Almacenar solo el hash es una buena idea, ha servido en el mundo de las contraseñas por décadas.

Agregar una sal parece una buena idea, y de hecho hace un ataque de fuerza bruta mucho más difícil para el atacante. Pero esa sal te costará mucho esfuerzo adicional cuando compruebes que un nuevo CC sea único: tendrás que SHA-1 tu nuevo CC número N veces, donde N es la cantidad de sales que tienes ya utilizado para todos los CC a los que lo está comparando. Si de hecho elige buenas sales aleatorias, tendrá que hacer el hash para cada otra tarjeta en su sistema. Entonces ahora estás haciendo la fuerza bruta. Entonces diría que esta no es una solución escalable.

Verá, en el mundo de las contraseñas una sal no agrega ningún costo porque solo queremos saber si el texto claro + sal hashecho lo que hemos almacenado para este usuario en particular. Tu requerimiento es bastante diferente.

Tendrá que sopesar el intercambio usted mismo. Agregar sal no hace que su base de datos sea segura si se la roban, simplemente hace que decodificarla sea más difícil. ¿Cuánto más difícil? Si cambia el ataque de 30 segundos a requerir un día, no ha logrado nada, aún se decodificará. Si lo cambia de un día a 30 años, ha logrado algo que vale la pena considerar.


@Cory R. King

SHA 1 no está roto, per se. Lo que muestra el artículo es que es posible generar 2 cadenas que tengan el mismo valor hash en menos tiempo de fuerza bruta. Aún no puede generar una cadena que iguale a un hash ESPECÍFICO en un período de tiempo razonable. Hay una gran diferencia entre los dos.


No almacene un SHA-1 simple del número de tarjeta de crédito, sería fácil de descifrar (especialmente dado que se conocen los últimos 4 dígitos). Tuvimos el mismo problema en mi empresa: así es como lo resolvimos.

Primera solución

  1. Para cada tarjeta de crédito, almacenamos los últimos 4 dígitos, la fecha de vencimiento, una sal larga aleatoria (50 bytes de largo) y el hash salado del número CC. Usamos el algoritmo hash bcrypt porque es muy seguro y puede ajustarse para que sea tan intensivo en CPU como lo desee. Lo sintonizamos para que sea muy caro (¡aproximadamente 1 segundo por hash en nuestro servidor!). Pero supongo que podrías usar SHA-256 e iterar tantas veces como sea necesario.
  2. Cuando se ingresa un nuevo número CC, comenzamos por encontrar todos los números CC existentes que terminan con los mismos 4 dígitos y tienen la misma fecha de vencimiento. Luego, para cada CC coincidente, verificamos si su hash salado almacenado coincide con el hash salado calculado a partir de su sal y el nuevo número CC. En otras palabras, verificamos si hash(stored_CC1_salt+CC2)==stored_CC1_hash .

Como tenemos aproximadamente 100k tarjetas de crédito en nuestra base de datos, necesitamos calcular aproximadamente 10 hashes, por lo que obtenemos el resultado en aproximadamente 10 segundos. En nuestro caso, esto está bien, pero es posible que desee ajustar bcrypt un poco. Lamentablemente, si lo hace, esta solución será menos segura. Por otro lado, si sintoniza bcrypt para que consuma más CPU, tardará más tiempo en coincidir con los números CC.

Aunque creo que esta solución es mucho mejor que simplemente almacenar un hash sin sal del número CC, no evitará que un pirata muy motivado (que logra obtener una copia de la base de datos) rompa una tarjeta de crédito en un tiempo promedio de 2 a 5 años. Entonces, si tienes 100k tarjetas de crédito en tu base de datos, y si el pirata tiene una gran cantidad de CPU, ¡entonces puede recuperar unos pocos números de tarjetas de crédito todos los días!

Esto me lleva a la creencia de que no debe calcular el hash usted mismo: tiene que delegar eso a otra persona. Esta es la segunda solución (estamos en el proceso de migrar a esta segunda solución).

Segunda solución

Simplemente haga que su proveedor de pagos genere un alias para su tarjeta de crédito.

  1. para cada tarjeta de crédito, simplemente almacena lo que quieras almacenar (por ejemplo, los últimos 4 dígitos y la fecha de vencimiento) más un alias de número de tarjeta de crédito.
  2. cuando se ingresa un nuevo número de tarjeta de crédito, contacta a tu proveedor de pagos y dale el número CC (o redirigir al cliente al proveedor de pagos, e ingresa el número CC directamente en el sitio web del proveedor de pagos). ¡A cambio, obtienes el alias de la tarjeta de crédito! Eso es. Por supuesto, debe asegurarse de que su proveedor de pago ofrezca esta opción y de que el alias generado sea realmente seguro (por ejemplo, asegúrese de que no calculen simplemente un SHA-1 en el número de tarjeta de crédito). Ahora el pirata tiene que romper su sistema más el sistema de su proveedor de pago si quiere recuperar los números de la tarjeta de crédito.

Es simple, es rápido, es seguro (bueno, al menos si tu proveedor de pago lo es). El único problema que veo es que lo vincula con su proveedor de pagos.

Espero que esto ayude.


Creo que he encontrado una forma infalible de resolver este problema. Alguien por favor corrígeme si hay un defecto en mi solución.

  1. Cree un servidor seguro en EC2, Heroku, etc. Este servidor cumplirá UN único propósito y SOLAMENTE uno de los propósitos: el hash de su tarjeta de crédito.
  2. Instale un servidor web seguro (Node.js, Rails, etc.) en ese servidor y configure la llamada REST API.
  3. En ese servidor, use una sal única (1000 caracteres) y SHA512 1000 veces.

De esa forma, incluso si los hackers obtienen tus hashes, tendrían que entrar en tu servidor para encontrar tu fórmula.


Si está usando un procesador de pago como Stripe / Braintree, permítales hacer el "trabajo pesado".

Ambos ofrecen huellas dactilares de la tarjeta que puede almacenar de forma segura en su db y comparar más adelante para ver si ya existe una tarjeta:

  • Stripe devuelve la cadena de fingerprint - ver el documento
  • Braintree devuelve unique_number_identifier string - ver doc