usuario procedimiento encriptar encriptada datos contraseña cifrado cambiar almacenado sql-server database security encryption passwords

sql-server - procedimiento - encriptar contraseña en base de datos



Método preferido para almacenar contraseñas en la base de datos (10)

¿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?


  1. almacena el hash de la contraseña salada, como bcrypt (notunce + 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. agregue un captcha 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 un enlace "Olvidé mi contraseña", asegúrese de que no envíe la nueva contraseña por correo electrónico, sino que envíe 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, asegurar el formulario de inicio de sesión (generalmente con HTTPS) y los servidores mismos

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

  1. => ataques de diccionario sin conexión
  2. => ataques de diccionario en vivo
  3. => ataques de denegación de servicio
  4. => todo tipo de ataques!

Como su pregunta es sobre el método y el tamaño de almacenamiento, lo abordaré.

El tipo de almacenamiento puede ser una 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 y SHA-512 tienen 32 y 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 quieres hacerlo bien, no deberías usar un hash único, 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 implementación .Net es RFC2892DeriveBytes http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx


Dado que el resultado de una función hash es una serie de bytes en el rango de 0 a 255 (o -128 a 127, dependiendo de la firma de su tipo de datos de 8 bits), almacenarlo 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 hash que usa. 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.

Con respecto a la "mejor" forma de realizar hash, he intentado proporcionar muchas respuestas a otras preguntas sobre ese tema:


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


Guardo el equivalente de hash salado de la contraseña en la base de datos y nunca la contraseña misma, luego siempre comparo el hash con el generado de lo que el usuario transfirió.

Es muy peligroso almacenar los datos de contraseñas literales 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.


Hago lo mismo que has descrito, excepto que está almacenado 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ás haciendo bien (dado que usas una Salt ).


Puede usar múltiples 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. A menudo uso entradas de contraseña como

{hashId} $ {salt} $ {hashed password}

donde "hashId" es solo un número que uso internamente para reconocer que, por ejemplo, estoy usando SHA1 con un patrón 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 hacerles cambiar su contraseña la próxima vez que inicien sesión.

Como han mencionado otros, debes tener cuidado con tus hash, ya que es fácil hacer algo que 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 quieres equilibre 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 usar 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 sugerí usar deliberadamente un algoritmo que grabase incluso una décima parte de un segundo para 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.


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

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

Si no necesitas algo demasiado elegante, esto es ideal para sitios web.

Si no está usando ASP.Net, aquí hay 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



Uso sha hash del nombre de usuario, un guid en la configuración web y la contraseña, almacenado 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 );