🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: es.comp.lenguajes.java
Article #655

Re: Almacenar contraseña

#655
From: Ricardo Palomares Martinez
Date: Fri, 16 Feb 2007 21:00
159 lines
7970 bytes
Guevonaso escribió:
> Tengo el siguiente dilema para una aplicación Swing que se conecta a
> un servidor, hasta ahora las contraseñas del usuario siempre las
> almacenaba encriptadas


Seguro que no, salvo que las metieses en una sala cerrada,
posiblemente excavada en la tierra, que es la única acepción que
podría entenderse, por cercanía lexicográfica, en caso de existir el
verbo "encriptar" en castellano, que no es el caso.

A lo mejor quieres decir "cifradas", que es la traducción al español
del inglés "encrypted". :-)


> con MD5 o SHA y las enviaba encriptadas y era
> el servidor el encargado de verificar que podria ser válida o no. Asi
> no hay problema al guardar una contraseña en la "plano" en un
> fichero .


No entiendo esto de último de "...en la "plano" en un fichero".
¿Quieres decir que no guardabas las contraseñas sin cifrar?

Hay maneras alternativas a la que describes tú arriba. Más abajo
comento algunas ideas.


> El problema ahora es que tengo que enviar la contraseña original, y
> por lo tanto no puedo hacerlo así. ¿Que otra manera tengo de almacenar
> esta contraseña en un fichero .properties de una manera segura?


¿Por qué tienes que enviar la contraseña "original" (imagino que
quieres decir "sin cifrar")? ¿Tienes el servidor bajo tu control, y
con el servidor quiero decir no sólo la administración, sino la API de
servicios que ofrece?

Yo creo que tienes que dividir el problema en dos partes: una es el
almacenamiento de la contraseña de una manera segura, y otra es la
manera de asegurar que un par usuario-contraseña introducido en el
extremo del cliente puede validarse de alguna manera fiable teniendo
los datos en el lado del servidor.

El primer problema es obvio, cifrar lo que guardas. MD5 y SHA son
algunas opciones, pero he creído leer por ahí que MD5 no es muy
seguro, y no sé si SHA también puede romperse por fuerza bruta con las
máquinas actuales. Dependiendo de la criticidad de la aplicación, yo
que tú me informaría un poco sobre algoritmos (creo recordar que había
un sustituto de DES que era bastante seguro, pero no recuerdo el
nombre). Por definición, los algoritmos de cifrado seguros son
aquellos en los que la seguridad no la aporta la ocultación del
algoritmo, por lo que no deberías tener problemas para encontrar el
código fuente de la mayoría de ellos.

Otra cosa que se suele hacer es no cifrar o aplicar una función hash a
la contraseña sin más, sino a la concatenación de una contraseña y una
pizca de sal (http://www.nmrc.org/pub/faq/hackfaq/hackfaq-04.html#4.6).



La segunda parte es harina de otro costal. Lo primero que sería
deseable es que la contraseña nunca viaje por la red, ya sea cifrada o
sin cifrar (y esto no sólo al iniciar sesión, sino al cambiar la
contraseña; interesante, ¿verdad?). Si para hacer la validación tienes
una función en el servidor que te pide la contraseña y no puedes
cambiar esa función por otra (a esto me refería con lo de "control del
servidor"), mal comienzo.

Te cuento cómo lo resolvía Novell antiguamente en sus clientes IPX
(una descripción la tienes aquí:
http://www.nmrc.org/pub/faq/hackfaq/hackfaq-20.html#20.8, pero
obviamente se salta algunos pasos, como que el cliente tiene que pasar
al servidor el nombre del usuario en claro en algún momento). La
"conversación" que tenía lugar entre un cliente que quería iniciar
sesión en un servidor NetWare y éste venía a ser así:

01- El cliente envia un paquete "HELLO" al servidor para iniciar la
    conversación de autenticación.

02- El servidor responde con un "HELLO" de cortesía, y en un par de
    intercambios de mensajes más se ponen de acuerdo en las versiones
    que tienen cada uno para encontrar el mejor algoritmo posible
    (probablemente tú no necesites esto, pero que sepas que puede ser
    un paso si vas a andar cambiando clientes y no todo el cambio se
    hará a la vez).

03- Una vez puestos de acuerdo, el cliente le dice al servidor cómo se
    llama el usuario (sin contraseña).

04- El servidor mira si el usuario existe y puede iniciar sesión
    (limitaciones horarias, de dirección de red, cuenta bloqueada,
    etc.). Si todo va bien, el servidor genera una semilla (un valor
    aleatorio) y la pasa al cliente.

05- El cliente, que tiene la contraseña en claro introducida por el
    usuario, usa un algoritmo hash (el mismo que en el servidor,
    claro) con la concatenación del usuario y la contraseña, y al
    resultado le vuelve a aplicar el algoritmo hash añadiendo la
    semilla. Así obtiene un valor único para la sesión, y lo envía al
    servidor.

06- El servidor hace lo mismo, y compara el resultado.

La contraseña no ha viajado en claro por la red, y no puede extraerse
de los paquetes que viajan fundamentalmente porque el algoritmo hash
es de un solo sentido (MD5 y SHA son algoritmos hash); si tienes el
nombre de usuario y el hash que has capturado por la red, no puedes
aplicar un algoritmo hash inverso para obtener la secuencia
usuario+contraseña. Además, la semilla es única por sesión.
Estadísticamente, para cuando consigas romper por fuerza bruta el
/cifrado/ con la semilla, la sesión habrá concluido.

A primera vista se me ocurre que quizá sería mejor usar una función de
cifrado reversible para la concatenación usuario+contraseña, pero no
sé ni de matemáticas ni de criptología lo suficiente para creer que
llevo razón. Una cosa que debes tener en cuenta es que el algoritmo
descrito en la URL que te paso tiene quince años; donde habla de 16 o
32 bytes puede que quieras doblar o cuadriplicar la longitud. En esa
época los ordenadores iban a 33 MHz, no a 3400. :-) Doblar la longitud
no supone doblar la dificultad, sino quizá multiplicarla por 2^128.

Por cierto, que en todo esto rollo verás que no he mencionado la
palabra "Java" ni una vez. Pero para que no quede tan "off-topic",
comentaré que durante finales de los 90, el CEO de Novell fue Eric
Schmidt, que lideró los inicios de Java. :-)

Hala, ya estamos on-topic. :-P

Windows NT usaba un esquema de desafío/respuesta, y creo recordar que
SSL también usa esto. Si buscas información sobre cómo funciona una
negociación de sesión de SSL, puedes obtener ideas básicas que
implementar.

Y ten presente que hay dos maneras de "robar" unas credenciales:
invirtiendo el cifrado de lo que viaja por la red, lo que no es
posible si se usan algoritmos hash, y probando combinaciones de
usuario y contraseña para iniciar sesión (ataque de fuerza bruta);
para esto último vienen bien las pizcas de sal y controles en el
servidor sobre intentos fallidos repetidos.

Saludos.

-- 
If it's true that we are here to help others,
then what exactly are the OTHERS here for?
Technical Details
Message-ID: <akiha4-199.ln1@Father.family>
Path: arc1-ca.pugleaf.net!g2news2.google.com!news2.google.com!news1.google.com!news.germany.com!aioe.org!Father.family!news
References: <1171611718.471822.142140@k78g2000cwa.googlegroups.com>

Show Full Headers
Complete Article Headers
X-Google-Thread: 1116f3,9d832e50e0797ac3
X-Google-Attributes: gid1116f3,public
X-Google-Language: SPANISH,ASCII
Path: arc1-ca.pugleaf.net!g2news2.google.com!news2.google.com!news1.google.com!news.germany.com!aioe.org!Father.family!news
From: Ricardo Palomares Martinez <rpm.PUBLI@iespana.es>
Newsgroups: es.comp.lenguajes.java
Subject: Re: Almacenar contraseña
Date: Fri, 16 Feb 2007 22:00:26 +0100
Organization: Hogar, dulce hogar
Lines: 159
Message-ID: <akiha4-199.ln1@Father.family>
References: <1171611718.471822.142140@k78g2000cwa.googlegroups.com>
NNTP-Posting-Host: ZpXS4kufLSNv31vt9Lrapw.user.aioe.org
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
X-Complaints-To: abuse@aioe.org
User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 Mnenhy/0.7.4.0