2009-03-05 18 views
75

¿Cuál es su método/tipo de datos preferido para almacenar contraseñas en una base de datos (preferiblemente SQL Server 2005). La forma en que lo he estado haciendo en varias de nuestras aplicaciones es primero usar las bibliotecas de cifrado .NET y luego almacenarlas en la base de datos como binario (16). ¿Es este el método preferido o debería usar un tipo de datos diferente o asignar más espacio que 16?Método preferido para almacenar contraseñas en la base de datos

+1

Tengo la sensación de que esto puede ser una víctima, pero lo que pensé puede ser una víctima de ella resultó ser referente a las conexiones reales DB y no sólo el almacenamiento de la aplicación/sitio inicios de sesión. – TheTXI

+1

¿Podría aclarar su pregunta para explicar si está utilizando funciones de "cifrado" o "hash"? Creo que te refieres a lo último, pero la diferencia es muy significativa. – ine

Respuesta

80

almaceno el equivalente de hash con sal de la contraseña en la base de datos y nunca la propia contraseña, a continuación, siempre comparar el hash a la generada de lo que el usuario se ha pasado.

Es demasiado peligroso para almacenar cada vez lo literal datos de contraseña en cualquier lugar. Esto hace que la recuperación sea imposible, pero cuando alguien olvida o pierde una contraseña, puede ejecutar algunas comprobaciones y crear una nueva contraseña.

+0

@Quinton: Eso es más o menos lo que hago. Con las librerías de encriptación de .net, reducirá la contraseña y luego la pasaré al DB y la almacenaré como un binario. Solo puedo comparar contraseñas mezclando la entrada del usuario y comparándola con lo que está almacenado. – TheTXI

+0

Parece que estás en el camino correcto. –

+1

Recomiendo jbcrypt si está trabajando con Java. Extremadamente simple de usar –

15

Hago lo mismo que ha descrito, excepto que se almacena como una cadena. I Base64 codifica el valor binario encriptado. La cantidad de espacio para asignar depende del algoritmo de encriptación/fuerza de cifrado.

Creo que lo está haciendo bien (dado que usa un Salt).

+2

+1 para abordar la verdadera pregunta aquí. – erickson

46

EL método preferido: nunca almacene contraseñas en su base de datos. Solo hash de eso. Agregue sal al gusto.

+5

mod up, tuve que hacerlo, solo por el chiste de sal;) – Jakub

+0

sonreí al verlo también. –

8

Dado que el resultado de una función hash es una serie de bytes en el rango 0 a 255 (o -128 a 127, dependiendo de la firma de su tipo de datos de 8 bits), almacenándolo como un campo binario sin procesar tiene más sentido, ya que es la representación más compacta y no requiere pasos adicionales de codificación y descodificación.

Algunas bases de datos o controladores no tienen una gran compatibilidad con los tipos de datos binarios, o a veces los desarrolladores simplemente no están lo suficientemente familiarizados con ellos como para sentirse cómodos. En ese caso, usar una codificación de binario a texto como Base-64 o Base-85, y almacenar el texto resultante en un campo de caracteres es aceptable.

El tamaño del campo necesario está determinado por la función de almohadilla que utiliza. MD5 siempre genera 16 bytes, SHA-1 siempre genera 20 bytes. Una vez que seleccionas una función hash, generalmente estás atascado con ella, ya que cambiar requiere un restablecimiento de todas las contraseñas existentes. Entonces, usar un campo de tamaño variable no te compra nada.


En cuanto a la "mejor" manera de realizar el hash, he tratado de dar muchas respuestas a otras preguntas sobre ese tema SO:

+0

Si lee mi pregunta un poco más de cerca, verá que estoy enfocado más en el almacenamiento real en términos de tipo de datos y espacio asignado para el campo. – TheTXI

+0

Pero +1 para proporcionar información adicional a otras personas que puedan venir más tarde. – TheTXI

+0

Derecho encendido. Parece que no soy el único que falta;) – erickson

8
  1. tienda el hash de la contraseña con sal, tales como bcrypt (nunciar + PWD). Es posible que prefiera bcrypt sobre SHA1 o MD5, ya que puede ajustarse para que consuma mucha CPU, lo que hace que un ataque de fuerza bruta sea más prolongado.
  2. añadir un código de imagen al formulario de inicio de sesión después de algunos errores de inicio de sesión (para evitar ataques de fuerza bruta)
  3. si su aplicación tiene vincular un "olvidado mi contraseña", asegúrese de que no envía la nueva contraseña por correo electrónico, sino que debe enviar un enlace a una página (segura) que permita al usuario definir una nueva contraseña (posiblemente solo después de la confirmación de cierta información personal, como la fecha de nacimiento del usuario, por ejemplo). Además, si su aplicación le permite al usuario definir una nueva contraseña, asegúrese de requerir que el usuario confirme la contraseña actual.
  4. y, obviamente, asegure el formulario de acceso (típicamente con HTTPS) y los servidores propios

Con estas medidas, las contraseñas de sus usuarios serán bastante bien protegidas contra:

  1. => offline ataques de diccionario
  2. => vivos ataques de diccionario
  3. => ataques de denegación de servicio
  4. => todo tipo de ataques!
+0

¡Todas estas medidas se pueden implementar rápidamente y atesoran un gran esfuerzo con el mínimo esfuerzo! +1 =) –

+0

¿Los ataques de DOS están relacionados con la seguridad de contraseñas? – Arj

+1

@ a12jun: si tiene un enlace "olvidé mi contraseña" en su sitio web con una simple entrada de "inicio de sesión", y un botón "por favor genere una nueva contraseña y envíelo por correo electrónico", cualquiera que conozca su nombre de usuario puede obligarte a cambiar tu contraseña. Si lo automatiza para que se ejecute cada 10 segundos, puede negarle el acceso a su cuenta. Si ejecuta esto en contra de miles de usuarios, es probable que a muchos de ellos les disguste su servicio. La Pauta # 3 puede protegerte contra esto, eso es lo que quise decir (no fue muy claro, debo admitirlo). Seguridad = Confidencialidad, Integridad, *** Disponibilidad ***. – MiniQuark

4

Un hash simple de la contraseña, o incluso (sal + contraseña) no es adecuado en general.

ver:

http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/

y

http://gom-jabbar.org/articles/2008/12/03/why-you-should-use-bcrypt-to-store-your-passwords

Ambos recomiendan los algoritmos Bcrypt. Implementaciones gratuitas se pueden encontrar en línea para la mayoría de los idiomas populares.

+0

Grandes enlaces que van más allá de las preocupaciones superficiales de seguridad. Para algoritmos deliberadamente lentos, ¿sería importante tener los hash calculados en el lado del cliente para no sobrecargar el servidor (posiblemente ya bastante ocupado)? – cheduardo

+0

No realmente. El objetivo es simplemente "Ligeramente" más lento. Solo para darte una idea. Puedo SHA1 hash sobre 200K contraseñas por segundo en el sistema de cuatro núcleos. Dudo que alguien necesite manejar 200K inicios de sesión simultáneos cada segundo ... Entonces usted usa una función como PBKDF2 o bcrypt para reducir la velocidad y decir solo 100 hashes por segundo (aumenta la línea de tiempo de la fuerza bruta en un factor de 200). –

2

Si está trabajando con ASP.Net puede usar la API integrada de membresía.

Admite muchos tipos de opciones de almacenamiento, incluso; hash unidireccional, cifrado bidireccional, md5 + salt. http://www.asp.net/learn/security para más información.

Si no necesita algo demasiado sofisticado, esto es ideal para sitios web.

Si no está utilizando ASP.Net aquí es un buen enlace a algunos artículos de 4guys y CodeProject

http://aspnet.4guysfromrolla.com/articles/081705-1.aspx http://aspnet.4guysfromrolla.com/articles/103002-1.aspx http://www.codeproject.com/KB/security/SimpleEncryption.aspx

4

uso el hash SHA del nombre de usuario, un GUID en la configuración web y la contraseña, almacenadas como varchar (40). Si quieren utilizar fuerza bruta/diccionario, también tendrán que hackear el servidor web para el guid. El nombre de usuario se rompe al crear una tabla rainbow en toda la base de datos si encuentran la contraseña. Si un usuario quiere cambiar su nombre de usuario, simplemente restablezco la contraseña al mismo tiempo.

System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(
    username.ToLower().Trim(), 
    ConfigurationManager.AppSettings("salt"), 
    password 
); 
+0

solía usar el nombre de usuario como sal agregada. Pero luego no pudimos cambiar el nombre de un usuario. Cambiamos a usar sal con la identificación del usuario, GUID, sid u otra clave sustituta. –

+0

tru, buena llamada. de esta manera no tiene que restablecer la contraseña cuando cambia el nombre de un usuario – Shawn

3

Puede utilizar múltiples valores hash en su base de datos, solo requiere un poco de esfuerzo extra. Aunque vale la pena, si crees que hay la menor posibilidad de que tengas que admitir formatos adicionales en el futuro.menudo voy a utilizar como entradas de contraseñas

{Hashid} $ {sal} $ {} contraseñas encriptado

donde "Hashid" es sólo un número utilizo internamente para reconocer que, por ejemplo, estoy usando SHA1 con un patrón de hash específico; "sal" es una sal aleatoria codificada en base64; y "contraseña hash" es un hash codificado en base64. Si necesita migrar hashes, puede interceptar personas con un formato de contraseña anterior y hacer que cambien su contraseña la próxima vez que inicien sesión.

Como han mencionado otros, debe tener cuidado con sus valores hash, ya que es fácil hacer algo eso no es realmente seguro, por ejemplo, H (sal, contraseña) es mucho más débil que H (contraseña, sal), pero al mismo tiempo desea equilibrar el esfuerzo puesto en esto con el valor del contenido del sitio. A menudo usaré H (H (contraseña, sal), contraseña).

Finalmente, el costo de usar contraseñas codificadas en base64 es modesto en comparación con los beneficios de poder utilizar varias herramientas que esperan datos de texto. Sí, deberían ser más flexibles, pero ¿estás listo para decirle a tu jefe que no puede usar su herramienta favorita de terceros porque quieres guardar unos pocos bytes por registro? :-)

Editado para agregar otro comentario: si sugiero usar deliberadamente un algoritmo que grabó incluso una décima parte de cada contraseña, sería una suerte que me echaran de la oficina de mi jefe. (¿No es tan afortunado? Anotaría algo para debatir en mi próxima revisión anual.) Quemar ese tiempo no es un problema cuando tienes docenas, o incluso cientos, de usuarios. Si está presionando a 100 mil usuarios, generalmente tendrá varias personas que inicien sesión al mismo tiempo. Necesitas algo rápido y fuerte, no lento y fuerte. El "pero ¿y la información de la tarjeta de crédito?" es falso en el mejor de los casos, ya que la información almacenada de la tarjeta de crédito no debería estar en ningún lugar cerca de su base de datos normal, y la aplicación la cifraría de todos modos, no a los usuarios individuales.

+0

No existe tal cosa como rápido y fuerte cuando se trata de hashing. Lo siento.Si es rápido para ti, es rápido para un atacante de fuerza bruta. El uso de una función de derivación de clave es un método válido para fortalecer la contraseña. –

2

Dado que su pregunta es sobre el método de almacenamiento & tamaño voy a abordar eso.

El tipo de almacenamiento puede ser de representación binaria o de texto (base64 es el más común). Binary es más pequeño pero me resulta más fácil trabajar con texto. Si está haciendo salting por usuario (sal diferente por contraseña), entonces es más fácil almacenar salt + hash como una sola cadena combinada.

El tamaño depende del algoritmo hash. La salida de MD5 siempre es de 16 bytes, SHA1 siempre es de 20 bytes. SHA-256 & SHA-512 son 32 & 64 bytes respectivamente. Si usa codificación de texto, necesitará un poco más de almacenamiento dependiendo del método de codificación. Tiendo a usar Base64 porque el almacenamiento es relativamente barato. Base64 va a requerir aproximadamente un 33% más de campo.

Si tiene salado por usuario, también necesitará espacio para el hash. Poniéndolo todo junto sal de 64 bits + hash SHA1 (160 bit) base64 codificada toma 40 caracteres, así que lo almaceno como char (40).

Por último, si desea hacerlo bien, no debería utilizar un solo hash, sino una función de derivación de teclas como RBKDF2. Los hashes SHA1 y MD5 son increíblemente rápidos. Incluso una sola aplicación con hebras puede cifrar contraseñas de entre 30 000 y 50 000 por segundo, lo que equivale a 200 000 contraseñas por segundo en la máquina de cuatro núcleos. Las GPU pueden usar hash 100x a 1000x tantas contraseñas por segundo. Con velocidades como esa, atacar con fuerza bruta se convierte en un método de intrusión aceptable. RBKDF2 le permite especificar el número de iteraciones para ajustar con precisión qué tan lento es su hash. El objetivo no es poner el sistema de rodillas, sino elegir una serie de iteraciones para que se limite el límite superior del rendimiento de hash (digamos 500 hashes por segundo). Un método a prueba de futuro sería incluir el número de iteraciones en el campo de contraseña (iteraciones + sal + hash). Esto permitiría aumentar las iteraciones en el futuro para seguir el ritmo de los procesadores más potentes.Para ser aún más flexible, use varchar para permitir hashes potencialmente más grandes/alternativos en el futuro.

La aplicación .Net es RFC2892DeriveBytes http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

Cuestiones relacionadas