MD5, javascript y seguridad

23 noviembre, 2010

A raíz de la aparición de Firesheep, he estado buscando información acerca de la creación de sistemas de login seguros. Me he llevado una gran sorpresa al comprobar que una de las recomendaciones que se hace en alguno de los foros es la de «encriptar» los passwords con MD5 desde Javascript. Son foros de cuyas direcciones no quiero acordarme, pero también en páginas serias se aconseja esta práctica sin explicar las limitaciones de la solución.

Aunque sea muy básico todo esto, voy a explicarlo por si alguien no lo tiene claro.

Un MD5(x) es simplemente una función de hash que transforma cualquier cadena de texto en una ristra de bits que se representa, también, por una cadena de texto. Por ejemplo:

MD5(«hola mundo») = «0ad066a5d29f3f2a2a1c7c17dd082a79″

Por lo que se utiliza en la codificación de contraseñas es porque siempre que a «hola mundo» le aplicas la función, te devuelve la misma ristra de bits.

El método «tradicional» es enviar el password (por ejemplo «hola mundo») al servidor y que allí se le aplique el MD5. Pero, pregunta importante ¿para que aplicar el MD5? Pues para que si alguna vez un hacker consigue acceder a los registros de la base de datos (que suele ser más fácil que acceder al servidor a nivel de usuario o superusuario) no pueda entrar en las cuentas de los usuarios con las contraseñas robadas.

Sabido esto, ¿que pasa si hacemos el MD5 en Javascript antes de enviar la petición? El password del usuario («hola mundo») se convierte en «0ad066a5d29f3f2a2a1c7c17dd082a79″ y ‘viaja’ así a través de la red. Si alguien lo captura no verá el password que el usuario ha tecleado, sino el password REAL. ¿Como que el password real? ¿Como puede ser? Ahí está el error de quienes piensan que simplemente por pasar el MD5 en Javascript el sistema de login es más seguro. Enviar la ristra «0ad066a5d29f3f2a2a1c7c17dd082a79″ sirve exactamente igual para acceder a la cuenta del usuario que con el sistema anterior enviar «hola mundo», pero con una salvedad: si ahora un hacker consigue leer la base de datos, habrá conseguido TODOS los passwords de los usuarios y podrá suplantarlos a todos.

Conclusión: si te limitas a hacer un MD5 en Javascript, en vez de más seguro, harás tu sistema más inseguro.

Pero, si Yahoo, por ejemplo, utiliza eso del MD5 en Javascript, será que tiene alguna utilidad. Sí, por supuesto. Aparte de quitarte de encima a algún script kiddie, te permite proteger a tus usuarios menos paranoicos, a esos que utilizan para todos los servicios el mismo usuario y la misma clave, ya que la contraseña que utilizan no se llega a transmitir por la red.

Y por último, ¿se pueden combinar ambas ventajas? Por supuesto que sí y es lo que no entiendo como no se explica cada vez que sale a relucir el tema de pasar el MD5. Si calculas el hash MD5 en JS para proteger a tus usuarios del lado de la red, protégelos también del lado del servidor haciendo un doble hash utilizando SHA1 en el servidor (o al revés).

Puedes descargarte una librería para calcular SHA1 y MD5 en javascript desde aquí.

Be Sociable, Share!

Tags: , , , ,
Posteado en Tecnologia | Comentarios (16)

16 Respuestas a “MD5, javascript y seguridad”

  1. admin dice:

    Ah, se me olvidaba comentar.. La única manera de protegerse de forma seria es usar https y aún así nadie está seguro.

  2. Alberto dice:

    Muchas gracias por la información. He estado a punto de meter la pata.

  3. Ramos dice:

    Muy interesante. La pregunta del millon seria:

    ¿cual es el sistema más seguro sin tener que usar SSL?

  4. morato dice:

    Pues nunca habia pensado en encriptar primero en javascript pq creo que con ssl es suficiente, pero si nos vamos a poner en plan paranoico, yo utilizaria un sha1 en el cliente, lo concatenaria con un password salt en el servidor y finalmente el doble hash en md5 (opcion b: «o al reves», asi solo guardamos 32bytes en el usr_password mas 32bytes en el usr_password_salt)
    #mode assange off

  5. Julio Toledo dice:

    Leí su comentario referente a la seguridad, o más bien la poca seguridad que presta un javascript al convertir una cadena de texto a MD5.
    Realmente creo que hay un problema en su apreciación, ya que si un hacker puede entrar a una base de datos, para qué le puede interesar una contraseña MD5 interceptada?

    En otras palabras, en la base de datos ya tiene toda la información que quisiera obtener sin necesidad de entrar como un usuario “clonado”.

    Si el hacker obtiene el MD5 no le servirá para entrar como usuario, a menos que tenga acceso a la base de datos, insisto, ya para qué?

    Si enfocamos el esfuerzo a evitar la intrusión en bases de datos por ejemplo un mysql dentro de un socket de seguridad, creo que la encriptación de información puede ser muy efectiva. (no infalible).

  6. admin dice:

    Quizás me expliqué mal o no entiendo lo que me comentas…

    Hay dos escenario, que el hacker haya accedido a la BBDD y que no.

    Si el hacker ha accedido a la BBDD puede ser por dos vías:
    a) El hacker ha conseguido root en el sistema, con lo cual entrar como un usuario es lo de menos… Descartamos esta vía.
    b) El hacker solo ha conseguido obtener acceso a parte de la BBDD dónde se almacenan las contraseñas. En ese caso si las contraseñas están guardadas en texto plano (error gigantesco) ya tiene acceso a la aplicación a través de cualquier usuario, y si están guardadas en MD5 habrá dos vías:
    b1) Que el programador haya implementado un sistema «normal» dónde el password se envía en texto simple y se codifica en el servidor, en cuyo caso al hacker de poco le servirá tener los códigos MD5 ya que no puede «volver atrás» y conseguir el texto plano que lo origina.
    b2) Que el programador haya implementado mal el sistema de codificación como se sugieren en algunos sitios de Internet y la encriptación se haga en el lado cliente y en el servidor se guarde sin más. En ese caso con ese MD5 el hacker puede acceder a través de cualquier usuario simplemente enviando el password como si fuera texto plano en el POST del formulario.

    Si el hacker no ha accedido a la BBDD, puede obtener el password a través de capturar el POST del formulario cuando el usuario hace login. En ese caso:
    a) Si el password no está encriptado el hacker tendrá acceso directo a esa cuenta (es lo que hace Firesheep).
    b) Si el password está encriptado en el lado cliente, con un poco más de dificultad pq tendrá que reproducir el POST de la página, pero también tendrá acceso a la cuenta.

    Lo que yo quería señalar es que frente a lo que se quiere proteger que es el posible robo de la contraseña en un entorno inseguro (Firesheep) el codificar en el lado cliente con MD5 no es la solución. En el caso de que pueda acceder al sistema, depende del grado de acceso que consiga, podrá interesarle entrar con la cuenta de un usuario (que puede ser la del administrador) o no.

    Espero que esto aclare un poco lo que quería decir en el artículo :)

  7. Julio Toledo dice:

    Te felicito por la manera en que tomaste mi comentario (muchos se ofuscan!!)
    Creo que tienes bien definida tu apreciación, en el escenario de que un hacker pudiera interceptar una contraseña, sea MD5 o tal cuál (fatídico!)
    Pero a lo que me refería en mi comentario es que tu observación era si el hacker lograba acceso a la base de datos, no al sistema en sí, cosa que yo no te aclaré muy bien. Ahora te entiendo y te doy toda la razón.

    Comentando tus incisos:

    a) No tendría sentido si lo que quiere es manipular información, lo que sería casi imposible ya que tendría que analizarla y saber qué está haciendo (codificación, relaciones, etc) creo que a lo que te refieres es a entrar al sistema y así manipular información (ej. consultas, ingresar información falsa, etc.)

    b1) de acuerdo, aunque como sabrás “dicen” que ya se han des encriptado los MD5, pero no dicen quién ni cómo (el clásico “el primo de un amigo…”)
    b2) Esto fue lo que no vi en tu post y lo que hace bueno tu análisis, pero como dices en el b) si sólo ha logrado entrar a la parte donde se almacenan las contraseñas se le complicará un poco realizar una pantalla con un POST ya que tendría que saber la configuración para conectarse a la BD, info que no tendría a la mano si entró, como dices, a una parte de la misma. Mi pregunta en este punto sería ¿Cómo entró a la BD?

    Si no ha accedido a la BD
    a) Completamente de acuerdo

    b) Aquí lo que me gustaría saber es qué tanto se captura de un POST si el código (en el caso de php) se ejecuta en el servidor, por tanto no “viaja” por la red. Esto es muy interesante ya que si lograra obtener código fácilmente puede reproducir lo que quiera, la cuestión es almacenar en otras carpetas del servidor como SSL el código de conexión a la BD, usuarios, etc.

    Lo que me ha interesado mucho es el tema de la instalación de mysql dentro de SSL para mayor seguridad, aunque como bien sabemos, la mayor parte de los accesos indebidos a la información de las empresas, es el descuido mismo de los usuarios.

    En fin, te agradezco te hayas tomado el tiempo para contestar mi correo, y los comentarios que haces, ya que me han servido de mucho.

  8. admin dice:

    Solo un matiz.. A lo que me refería con eso de capturar el POST no es otra cosa que lo que hace firesheep, que es capaz de pillar al vuelo la información que va del cliente al servidor en un formulario como este:

    [form action=»http://servidor.com» method=»post»]
    [input type=»password» name=»pwd» /]
    [input type=»submit»/]
    [/form]

    Imagina ese caso. Si el hacker ha conseguido capturar la transmisión tendrá una cadena que dirá algo así como:

    pwd=HolaMundo

    Bien, si el programador la ha codificado con MD5 tendrá en su lugar algo como esto:

    pwd=e99008846853ff3b725c27315e469fbc

    Supongamos el caso b2, para el hacker sería tan fácil entrar en el sistema con la cuenta de otro usuario como hacer un HTML con esto:

    [form action=»http://servidor.com» method=»post»]
    [input type=»password» name=»pwd» value=»e99008846853ff3b725c27315e469fbc» /]
    [input type=»submit»/]
    [/form]

    Es decir, está igual de protegido como si no hubiera hecho nada y, peor, los passwords en la base de datos los tendrá sin codificar por lo que si algún atacante consigue hacer un volcado de la misma (hay maneras) podrá entrar con cualquier cuenta con el script anterior.

  9. Fastest dice:

    admin, estás totalmente equivocado, si captura el md5, llegará al servidor y cualquier programador decente recibirá el POST y lo codificará nuevamente en el servidor, es ahí que recién compara. no lo hace en la misma PC (es un primer anillo de seguridad).

    saludos.

  10. admin dice:

    Fastest, creo que no te has leído el artículo, ¿verdad? Este es el último párrafo del mismo:

    Y por último, ¿se pueden combinar ambas ventajas? Por supuesto que sí y es lo que no entiendo como no se explica cada vez que sale a relucir el tema de pasar el MD5. Si calculas el hash MD5 en JS para proteger a tus usuarios del lado de la red, protégelos también del lado del servidor haciendo un doble hash utilizando SHA1 en el servidor (o al revés).

  11. Daniel dice:

    Que tal estoy trabajando en un proyecto y pues en búsqueda de aumentar la seguridad en el envió de la contraseña quisiera tu opinión auditoria
    Paso a decirte lo que hago lo básico
    Enviar el formulario por POST y la contraseña pos va en texto plano y en el servidor le aplico MD5 y la guarda en Mysql

    Y ahora lo que tengo en mente es inicio sección en php y obtengo el session_id() con este lo que hago en JavaScript md5(md5(Contraseña)+idSesión) y así se envía por Post (incluso si uso get se ve el MD5) asi el md5 enviado cambia cada sección del navegador mente he igual se sigue almacenando en la base de datos como md5(Contraseña) así que genero la consulta le agrego el idSesión y los paso por md5 y los comparo.

    Como ves el método o estoy haciendo muchos paso y no sirve de nada y no dificulto nada el hackeo????

    (Desconozco si el idSesión se pueda forzar y el idSeccion se puede conocer por que se pasa como una variable de texo plano directo en javascrip si miras el código del navegador hay te viene)

    Y cundo guardo la contraseña al generar el usuario esa si va en md5(contraseña) por JavaScript y así se almacena en mysql (Que esa es otro aspecto que no se tocó en el tema)

    Gracias si les interesa el código se los proporciono.

  12. admin dice:

    Sí, Daniel, creo que estás haciendo demasiado trabajo para nada, ya que cualquier ataque MotM va a poder reproducir el acceso al sistema. Si el sistema requiere de verdad de seguridad, yo me decantaría por instalar un servicio HTTPS. Puede ser gratis si no te importa que salga un letrero de advertencia (Intranets o SaaS para empresas) o puedes pagar un poco (unos 60$) y obtener un certificado válido. El resto de acciones, bueno, pueden confundir al hacker principiante, pero al final son fácilmente vulnerables.

  13. Daniel dice:

    Si tiene razón ya me puse a analizar y en si cual quiere cosa que agás en el cliente (JavaScript) pues es fácil de leer y solo lo que hace es confundir un poco que no siempre envía el mismo per al leer el JavaScript hay sale todo

    Y que opinas de este método de aquí lo quise basar solo que desconvoco mucho de Ajax

    http://www.edgaragg.com/index.php?option=com_content&view=article&id=49%3Aautenticacion-ajax&catid=34%3Asecurity&Itemid=53&showall=1

    la verdad no tengo ni idea como aplicarlo y realmente no lo necesito sino es solo por conocimiento el sistema que estoy haciendo se usara en una Red local y los usuarios al mucho son expertos per en Facebook

    Pero muchas gracias así cundo requiera algo mas de seguridad contratare un certificado SSL

  14. Ivan dice:

    Ese método es muy parecido al que hace un SSL, pero claro, vía JS puede resultar un poco lento (aunque si solo lo utilizas para las credenciales no es un problema). La pregunta que debes hacerte es ¿merece la pena? si tus usuarios no son expertos la respuesta creo que es «no» :)

  15. xkz dice:

    Muchas gracias por el artículo!! Tengo dos preguntas:

    1) No comprendo lo de «si ahora un hacker consigue leer la base de datos, habrá conseguido TODOS los passwords de los usuarios y podrá suplantarlos a todos.» ¿Simplemente tiene el texto plano y el encriptado y es capaz de sacar el resto, y en cambio con el procesado en el servidor sólo tiene la contraseña «definida» de un único usuario? (Discúlpame pero soy muy novato todavía)

    2) Al usar MD5, seguiría siendo necesaria la atención prestada frente a vulnerabilidades sql y xss? ¿O al almacenarlas encriptadas ya no tiene sentido?

    Muchas gracias y un saludo

  16. Ivan dice:

    1) El hacker (que en principio NO tiene que tener acceso a ningún password, solo aprovecharse de alguna vulnerabilidad para acceder a la BBDD) podría hacer una consulta del tipo «SELECT * FROM user» y obtener directamente los passwords encriptados. Con un simple HTML que se salte la encriptación, se podría impersonar a cualquier usuario.

    2) Ambas son necesarias.

Dejar un comentario