Ola, somos Arume

Desenvolvemos páxinas web, aplicacións para móbiles, capas de realidade aumentada e aplicacións para Facebook. Apaixónanos a informática e somos uns perfeccionistas incurables; por eso nos nosos proxectos utilizamos estándares.

tel. 625 519 694

Félix Acevedo, 13, 2º B, 15008, A Coruña

Autenticarse

Rexistrarse. Esqueceches o teu contrasinal?

Etiquetas

Saltar as etiquetas

Subscríbete ás RSS

Estás en:

  • Inicio >
  • Blog >
  • Encriptar e gardar contrasinais en base de datos

Encriptar e gardar contrasinais en base de datos

16 Feb 2011 por Luis

Comentarios: 10

Top secret

Sempre que se deseña unha aplicación que necesite identificación de usuarios suscítase a dúbida de se utilizar un sistema de autenticación externo (Facebook, Google , OpenId, ...) ou un sistema de autenticación propio. Cando se utiliza un sistema de autenticación propio, exponse o problema da seguridade á hora de gardar os contrasinais dos usuarios na nosa base de datos.

Aparentemente é un problema menor, xa que, á fin e ó cabo, o contrasinal dun usuario para o noso foro ou blog non parece unha información crítica. E isto sería así se non fose porque se sabe que moitos usuarios reutilizan os seus contrasinais en diferentes sitios. Se o unimos a que a conta de email é tamén un dato que se adoita pedir, calquera atacante que consiga roubar os contrasinais dun pequeno foro ou blog acabará cos contrasinais das contas de email, facebook, ... de moitos dos seus usuarios.

Ademais das medidas para evitar os ataques por forza bruta (pedir contrasinais cun número mínimo de carácteres, que conteñan maiúsculas, minúsculas, carácteres especiais e números, bloquear repetidos intentos de acceso errado, ...) e outros, hai que ter en conta a posibilidade de que se comprometa a nosa base de datos ou un backup da mesma.

Protexendo os contrasinais

Nunca debemos gardar os contrasinais dos usuarios sen cifrar. Isto é un erro máis común do que poida parecer xa que os clientes adoitan pedir como requisito o que se poida "recordar" o contrasinal ós usuarios (enviar por correo o contrasinal actual, non un novo).

Os contrasinais sempre han de gardarse na base de datos "cifrados" dalgún modo, de forma que o atacante non poida coñecelos. Se é requisito indispensable o que os contrasinais poidan ser "recordadas", deberán cifrarse cun algoritmo de "dobre sentido" para que poidan ser descifrados pola aplicación. Pero este sistema é moi pouco recomendable xa que o atacante poderá tamén descifralos. O mellor é cifrar os contrasinais cun algoritmo de "un só sentido" de forma que non se poidan descifrar.

Encriptando os contrasinais

En realidade, aínda que seguiremos chamándolle "encriptado" por comodidade, o que se adoita facer é pasar os contrasinais por unha función resumen como función resumen como MD5, SHA, ..., gardar na base de datos o "resumen" xerado e descartar o contrasinal.

$hash = sha1($password);
unset($password);
// Se $password == 'apple'
// $hash == 'd0be2dc421be4fcd0172e5afceea3970e2f3d940'

Máis adiante, para comprobar se un usuario puxo ben o seu contrasinal, o que faremos será encriptar o que o usuario nos envía e comparar o resultado do cifrado co que temos na nosa base de datos.

// $db_hash será o que temos gardado na base de datos
if ($db_hash === sha1($password))
{
	// Contrasinal correcto
}

Así, aínda que se comprometa a nosa base de datos, o atacante non poderá coñecer os contrasinais dos usuarios de forma fácil. O único que lle queda para poder descifralos é un ataque por forza bruta ou por táboas rainbow (táboas con cadeas de carácteres e o resultado de cifralas con algunhas funcións de resumo).

Elexir un algoritmo de cifrado

As funcións de resumo máis coñecidas e utilizadas son MD5 e SHA-1, pero dado que MD5 e SHA-1 foron comprometidas, actualmente estanse impondo novas funcións como son SHA-2 e Bcrypt.

Á hora de escoller unha delas para a nosa aplicación, deberemos ter en conta ademais da dispoñibilidade que teñamos, a velocidade de execución da función. Neste caso, ó contrario que na maioría dos casos en computación, a que máis nos interesa é a máis lenta (Bcrypt). A razón é que nós só imos cifrar un contrasinal ó identificarse un usuario. Non importa que este proceso leve 0.001 segundos ou 0.3 segundos. Con todo, para un atacante, esta diferenza fai que xerar táboas rainbow poida tardar dunhas horas a varios anos.

Engadindo sementes

Outra forma de porllo difícil ó atacante é engadir unha semente ó contrasinal antes de pasalo pola función resumen. Desta forma, aínda ten máis complicado utilizar as táboas rainbow, ó facer a cadea do contrasinal máis longa e máis improbable que estea na táboa rainbow.

Para porllo aínda peor, o mellor é que a semente sexa única para cada contrasinal, de forma que non poida facerse unha táboa rainbow coa túa semente incorporada, senón que tería que facerse unha táboa para cada contrasinal.

A forma de facelo sería así:

$salt = md5(uniqid(rand(), true)); // Ou ata mellor se tivese maiúsculas, minúsculas, carácteres especiais...
$hash = hash('sha512', $salt.$password); // Pode porse diante ou detrás, é igual
unset($password);
// Gardar en base de datos o $hash e $salt

Logo, cando queiramos autenticar un usuario:

// $db_salt será a semente que teremos en base de datos
// $db_hash será o resumo que temos gardado na base de datos
if ($db_hash === hash('sha512', $db_salt.$password))
{
	// Contrasinal correcto
}

Con este método, aínda que dous usuarios teñan o mesmo contrasinal, será imposible sabelo xa que o seu resumo será distinto.

Comentarios

10 comentarios. Comentar.

1. Danielo o 01 Xul 2011 ás 23:26:16

Genial! Justo la información que buscaba como punto de partida para empezar con el modulo de identificación de mi sitio web. Muchas gracias por el artículo.

2. Luis o 04 Xul 2011 ás 10:58:10

Nos alegra ser de ayuda.

De todas formas recuerda que en los casos en que es importante la seguridad, siempre es mejor utilizar software ya creado y testeado por la comunidad que reinvertar la rueda.

3. Emilio o 26 Ago 2011 ás 05:14:07

Muy buen post. Es muy importante tener éstas cosas en cuenta para garantizar al menos cierto nivel de seguridad por nuestra parte. Lástima que la gente hace pavadas como poner la misma contraseña tanto para la cuenta del banco como para Facebook, y encima conectarse desde redes sin encriptar ó con WEP (un par de segundos de diferencia nomás xD) en lugares muy concurridos, ó entrar a páginas de login clonadas.

Me sirve a mí también el artículo :)

Saludos.

4. Anónimo o 12 Xuñ 2012 ás 01:05:24

pues mui buena su explicacion pero creo q aun le fla musho massss

5. Anónimo o 20 Ago 2012 ás 15:32:45

hola, muy buena explicacion.

me gustaria saber como hacer para que una sea reemlasada por una nueva en la base de datos...

logre que eliminara la contraseña vieja pero ahora no me quiere guardar la nueva.....

que tengo a hacer..????

6. Luis o 21 Ago 2012 ás 10:54:23

Hola Anónimo.

No entiendo nada de lo que dices en tu comentario. Si quieres que te ayuden deberías explicarte mejor y al menos esforzarte un poco al describir tu problema.

Supongo que "reemlasada" quiere decir "reemplazada", pero aún así no puedo ayudarte, ya que en el artículo no hablo para nada sobre consultas a una base de datos y tú tampoco nos explicas cómo eliminas la vieja ni cómo intentas guardar la nueva.

7. Alex!!! o 29 Ago 2012 ás 02:34:28

holaaaaa como van buen post.. yo ando keriendo saber si en mi blog puedo meter un boton de usuario y contraseña y q dicha informacion se almacene en algun lado para tener un control de la misma..

osea en simples palabras.. quiero que la gente q entre en mi blog y deva poner cualquier usuario y contraseña como primera ves y quiero tener control de esa informacion.... si me ayudan se los agradeceria...

llevo tiempo tratando de hacerlo.. pero como saben en internet hay mucha basura inserbible...!!!!

bueno si pueden ayudarme.. o entender bn lo que quiero hacer por favor podrian escribirme a mi mail o almsn asi poder hablar trankilos..

desde ya muchas gracias.. agradecidoooo!!! ^^ que sigan bien!!!

P/D es muy importante que me ayuden... ^^ muchas gracias nuevamente....

8. Luis o 29 Ago 2012 ás 11:15:56

Hola Alex!!!

No se que tipo de blog estarás usando para que no traiga esa funcionalidad por defecto.

De todas formas, nosotros somos una empresa, nos ganamos la vida haciendo y modificando páginas web. Si tienes alguna duda puntual podemos ayudarte a resolver el problema (siempre a través del blog para que sirva como referencia a otras personas con el mismo problema), pero lo que no podemos hacer es trabajar gratis para ti ni formarte en programación web.

Si lo que quieres es contratarnos para que hagamos algún trabajo en tu página web, puedes ponerte en contacto con nosotros a través de nuestro email o por teléfono (nuestros datos están debajo del logo).

Aprovecho para hacerte un favor y elimino tu email de tu comentario.

Un saludo.

9. tecop o 09 Feb 2013 ás 09:20:12

Hola, al recuperar el "salt" de la base de datos y hacer "hash('sha512', $db_salt.$password)", me sale un "hash"diferente.

La cosa es que lo compruebo aparte con el "salt" devuelto y si me sale el "hash".

No se que es, ¿Podrían ser espacios en blanco que no se vean?

Gracias y saludos

10. Luis o 09 Feb 2013 ás 11:51:16

Hola tecop.

Lo siento pero no entiendo el problema. Según me dices en un "sitio" haces "hash('sha512', $db_salt.$password)" y te sale un hash pero en otro "sitio aparte" haces eso mismo y te da otro hash distinto. ¿Es así? Porque si es así creo que está claro que $db_salt y/o $password no valen lo mismo en el "sitio" y en el "sitio aparte".

Sin más datos no puedo ver cual es el problema. Lo que yo haría sería hacer un "echo" de $db_salt y $password en el "sitio" para comprobar que esos datos son correctos antes de cifrarlos. Si ese no es el problema vería si hay algún "caracter especial" (vocales con tilde, eñes, ...) y si tienes algún problema de codificación de caracteres (que la base de datos esté en utf-8 y el archivo en ISO-8859-1 o algo así).

Un saludo.

Comentar

Comentar de forma anónima

Podes comentar poñendo calquera nome ou alcume, exceptuando os nomes de usuarios rexistrados. Máximo de 50 caracteres.

Comentar como usuario rexistrado

Rexistrarse. Esqueceches o teu contrasinal?