2008-09-19 9 views
17

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 las tarjetas de crédito y las fechas de vencimiento.La mejor manera de evitar el uso duplicado de tarjetas de crédito

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 hash para determinar si una tarjeta se ha utilizado anteriormente.

Por lo general, se usa una sal 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.

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

Respuesta

0

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

0

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

+0

Estoy de acuerdo. Tenga en cuenta que esto hace que el registro de una tarjeta de crédito sea una operación O (n) donde n es el número existente de tarjetas registradas. Además, el hashing es una operación bastante costosa. – Johan

1

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 this Coding Horror article:

Añadir una sal aleatoria larga, única para cada contraseña se almacena. 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.

+0

Sí, pero si utiliza una sal aleatoria diferente para cada hash, debe probar cada sal en el nuevo valor que desea comparar. Use una cadena larga aleatoria pero constante + fecha de vencimiento. –

+0

Si está utilizando la fecha de caducidad en la sal, ¿cómo es constante? – ine

+0

A menos que estén usando un diccionario que incluya la fecha de caducidad como sal. –

1

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 como una buena idea, y de hecho hace un ataque de fuerza bruta que es 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.

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

Tendrás que sopesar el cambio. 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 has 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.

+0

Ah, y si SHA-1 es tan caro que agregar esa sal de hecho le costará al hacker años, entonces también va a ser tan costoso que probablemente sufrirá agregar CC número 10,000. Pero siempre puede probarlo frente a su tamaño de base de clientes esperado y ver si duele o no. – Jeff

+2

-1 Lo siento, pero realmente no estoy de acuerdo con esta respuesta: no se pueden tratar números de tarjetas de crédito como contraseñas, porque las personas pueden elegir contraseñas complejas si es necesario (largas, con letras, dígitos y caracteres especiales), mientras que los números de tarjetas de crédito son solo alrededor de 16 dígitos, y la mitad se pueden adivinar fácilmente (los primeros 7 son estándares de la industria (ver la respuesta de Nick Johnson), y los últimos 4 se almacenan en la base de datos, según la pregunta (y esta es una práctica común). realmente * no * almacene "solo el hash". En su lugar, siga la respuesta de Wedge o la mía – MiniQuark

+1

-1 MiniQuark tiene razón. Este esquema es inferior a otras propuestas hechas aquí. El hecho de que las tarjetas de crédito podrían simplemente ser adivinadas no se trata aquí. – Accipitridae

0

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

+1

Tanto SHA1 como MD5 solo se rompen porque es posible generar dos cadenas con el mismo hash. Ninguno de los dos se rompe cuando se trata de calcular preimágenes para un hash, o cuando se trata de generar una cadena con el mismo hash que una cadena conocida. –

0

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?

+0

Sí, lo haría, el punto es que los ataques basados ​​en tablas tardan mucho tiempo en generarse. Si tiene una sal diferente para cada número de tarjeta, la construcción de la tabla solo le permitirá, como máximo, 1 tarjeta. El costo no vale la pena. –

+0

Estaba defendiendo contra el hash salado: creo que es excesivo cuando el propósito del OP es simplemente evitar múltiples instancias de datos que, por sí mismos, no son lo suficientemente únicos como para que coincidan. –

0

Creo que una buena solución, como se indicó anteriormente, sería almacenar un valor hash de, digamos, Número de tarjeta, Fecha de caducidad y Nombre. De esa manera usted todavía puede hacer comparaciones rápidas ...

2

@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.

0

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.

3

PCI DSS indica que puede almacenar PAN (números de tarjeta de crédito) utilizando un fuerte hash de un sentido. Ni siquiera requieren que sea salado. Dicho esto, deberías salarlo con un valor único por tarjeta. La fecha de caducidad 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 tarjetas de crédito válidos e intentar 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.

10

La gente está pensando demasiado 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, luego realice el control definitivo de alto costo solo si se produce ese impacto.

Paso 1:

buscar coincidencias con los últimos 4 dígitos (y posiblemente también la fecha del exp, aunque hay algunas sutilezas ahí que puedan necesitar de direccionamiento.).

Paso 2:

Si las visitas de verificación simples, utilice la sal, obtener el valor de hash, hacer la comprobació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 control LUHN), por lo que el porcentaje de controles en profundidad no coincidirá (la tasa de falsos positivos) será muy, muy bajo (una fracción de un porcentaje), lo que le ahorrará una gran cantidad de gastos generales en comparación con el ingenuo diseño de "compruebe el hash cada vez".

+0

Eso suena como una buena idea, para hacer los últimos 4 dígitos de verificación antes de comparar hashes. ¡Gracias! –

+2

Almacenar los últimos 4 dígitos simplifica aún más un ataque de fuerza bruta. –

+0

@Arachnid Tristemente, almacenar los últimos 4 dígitos es una práctica común para los comerciantes. Sin embargo, puede comparar con la fecha de vencimiento como la primera prueba si no desea mantener los últimos 4 dígitos. – Wedge

17

Vamos a hacer 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 se busca algo que da puntos de referencia algoritmo de hash, encontré this article about storing credit card hashes, que dice:

Almacenamiento de tarjetas de crédito mediante un sencillo de un solo paso de un algoritmo de control, incluso cuando se sala, es fool- resistente. 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 hash número de tarjeta de crédito, el hash debe ser cuidadosamente diseñado para proteger contra ataques de fuerza bruta mediante el uso de fuertes funciones criptográficas de hash disponibles, los valores de sal grandes y múltiples iteraciones.

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.

5

Do no un simple almacén de SHA-1 del número de tarjeta de crédito, sería manera a fácil de descifrar (especialmente desde 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 caducidad, una sal aleatoria de longitud (longitud de 50 bytes), y el hash con sal del número de CC. Usamos el algoritmo hash bcrypt porque es muy seguro y se puede sintonizar para que consuma tanto 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 o no.

Dado que tenemos aproximadamente 100k tarjetas de crédito en nuestra base de datos, tenemos que 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 manera mejor que simplemente almacenar un hash sin sal del número de CC, no va a impedir que un pirata muy motivado (que logra obtener una copia de la base de datos) para romper un crédito tarjeta en un tiempo promedio de 2 a 5 años. Entonces, si tiene 100k tarjetas de crédito en su base de datos, y si el pirata tiene un lote de CPU, ¡entonces puede recuperar algunos 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 tienen su proveedor de pago genera un alias para su tarjeta de crédito.

  1. para cada tarjeta de crédito, sólo tiene que almacenar todo lo que desea almacenar (por ejemplo, los últimos 4 dígitos & la fecha de vencimiento) más un número de tarjeta de crédito alias.
  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 su proveedor de pago es). El único problema que veo es que lo vincula con su proveedor de pagos.

Espero que esto ayude.

2

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 servirá UNA SOLA finalidad y SOLO un propósito: 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 a la API REST.
  3. En ese servidor, use una sal única (1000 caracteres) y SHA512 1000 veces.

esa manera, incluso si los hackers obtienen sus valores hash, lo que necesitaría ser entrar en su servidor para encontrar su fórmula.

0

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

Ambos huellas digitales oferta de tarjetas que se pueden almacenar de forma segura en su base de datos y comparar más tarde para ver si una tarjeta ya existe:

  • raya vuelve fingerprint cadena - ver doc
  • Braintree vuelve unique_number_identifier string - ver doc
Cuestiones relacionadas