2009-01-14 25 views
71

Los archivos Java .class se pueden decompilar con bastante facilidad. ¿Cómo puedo proteger mi base de datos si tengo que usar los datos de inicio de sesión en el código?¿Cómo puedo proteger el nombre de usuario y la contraseña de MySQL de la descompilación?

+0

Espero que no te moleste, he retomado tu pregunta. Eliminé "nombre de usuario" y "contraseña" y agregué "ingeniería inversa" y "descompilación". Creo que son más descriptivos que los originales. ¡Excelente pregunta sobre los fundamentos, por cierto! –

+5

Tenga en cuenta que el hecho de que esté usando Java no es realmente relevante aquí. Tener contraseñas codificadas en cualquier idioma es problemático de la misma manera ("strings thebinary" también muestra las constantes de cadena en los programas C). –

+0

@saua: Es cierto, pero tal vez alguien publique algún código de muestra sobre cómo desacoplar nombres de usuario y contraseñas en Java. Incluso podría hacerlo yo mismo si tuviera tiempo. –

Respuesta

105

Nunca codifique las contraseñas en su código. Esto se produjo recientemente en el Top 25 Most Dangerous Programming Mistakes:

-duro de codificación de una cuenta secreta y contraseña en su software es extremadamente conveniente - de ingenieros cualificados inversa. Si la contraseña es lo mismo en todo su software, , entonces cada cliente se vuelve vulnerable cuando esa contraseña inevitablemente se convierte en conocida. Y como está codificado, es un gran problema repararlo.

Debe almacenar la información de configuración, incluidas las contraseñas, en un archivo separado que la aplicación lee cuando se inicia. Esa es la única manera real de evitar que la contraseña se filtre como resultado de la descompilación (para empezar, nunca compilarla en el binario).

Para obtener más información acerca de este error común, puede leer el CWE-259 article. El artículo contiene una definición más completa, ejemplos y mucha otra información sobre el problema.

En Java, una de las formas más fáciles de hacer esto es usar la clase de Preferencias. Está diseñado para almacenar todo tipo de configuraciones de programa, algunas de las cuales podrían incluir un nombre de usuario y contraseña.

import java.util.prefs.Preferences; 

public class DemoApplication { 
    Preferences preferences = 
     Preferences.userNodeForPackage(DemoApplication.class); 

    public void setCredentials(String username, String password) { 
    preferences.put("db_username", username); 
    preferences.put("db_password", password); 
    } 

    public String getUsername() { 
    return preferences.get("db_username", null); 
    } 

    public String getPassword() { 
    return preferences.get("db_password", null); 
    } 

    // your code here 
} 

En el código anterior, se puede llamar al método setCredentials después de mostrar un diálogo para askign el nombre de usuario y contraseña. Cuando necesite conectarse a la base de datos, puede usar los métodos getUsername y getPassword para recuperar los valores almacenados. Las credenciales de inicio de sesión no estarán codificadas en sus binarios, por lo que la descompilación no representará un riesgo de seguridad.

Nota importante: Los archivos de preferencias son simplemente archivos XML de texto sin formato. Asegúrese de tomar las medidas adecuadas para evitar que usuarios no autorizados vean los archivos sin formato (permisos de UNIX, permisos de Windows, etc.). En Linux, al menos, esto no es un problema, porque llamar al Preferences.userNodeForPackage creará el archivo XML en el directorio de inicio del usuario actual, que de todos modos no será leído por otros usuarios. En Windows, la situación puede ser diferente.

Notas más importantes: Hubo mucha discusión en los comentarios de esta respuesta y otros sobre cuál es la arquitectura correcta para esta situación. La pregunta original no menciona realmente el contexto en el que se está utilizando la aplicación, por lo que hablaré sobre las dos situaciones en las que se me ocurre. El primero es el caso en el que la persona que usa el programa ya conoce (y está autorizada para saber) las credenciales de la base de datos. El segundo es el caso en el que usted, el desarrollador, intenta mantener en secreto las credenciales de la base de datos de la persona que usa el programa.

Caso Primero: se autoriza usuario conocer las credenciales de acceso de base de datos

En este caso, la solución que he mencionado anteriormente funcionará. La clase Java Preference almacenará el nombre de usuario y la contraseña en texto plano, pero el archivo de preferencias solo será legible por el usuario autorizado. El usuario puede simplemente abrir el archivo XML de preferencias y leer las credenciales de inicio de sesión, pero ese no es un riesgo de seguridad porque el usuario ya sabía las credenciales.

Segundo caso: Tratando de ocultar las credenciales de acceso del usuario

Este es el caso más complicado: el usuario no debe conocer las credenciales de inicio de sesión, pero todavía necesita el acceso a la base de datos. En este caso, el usuario que ejecuta la aplicación tiene acceso directo a la base de datos, lo que significa que el programa necesita saber las credenciales de inicio de sesión con anticipación. La solución que mencioné arriba no es apropiada para este caso. Puede almacenar las credenciales de inicio de sesión de la base de datos en un archivo de preferencias, pero el usuario podrá leer ese archivo, ya que será el propietario. De hecho, realmente no hay una buena manera de usar este caso de forma segura.

Caso correcta: El uso de una arquitectura de varios niveles

La forma correcta de hacerlo es tener una capa media, en medio de su servidor de base de datos y la aplicación cliente, que autentica a los usuarios individuales y permite una limitada conjunto de operaciones a realizar. Cada usuario tendría sus propias credenciales de inicio de sesión, pero no para el servidor de la base de datos. Las credenciales permitirían el acceso a la capa intermedia (el nivel de lógica de negocios) y serían diferentes para cada usuario.

Cada usuario tendría su propio nombre de usuario y contraseña, que podrían almacenarse localmente en un archivo de preferencias sin ningún riesgo de seguridad. Esto se llama three-tier architecture (los niveles son su servidor de base de datos, servidor de lógica de negocios y aplicación de cliente). Es más complejo, pero realmente es la forma más segura de hacer este tipo de cosas.

El orden básico de las operaciones es:

  1. cliente se autentica con capa de lógica de negocio utilizando personales nombre de usuario/contraseña del usuario. El nombre de usuario y la contraseña son conocidos por el usuario y no están relacionados con las credenciales de inicio de sesión de la base de datos de ninguna manera.
  2. Si la autenticación tiene éxito, el cliente realiza una solicitud al nivel de lógica de negocios solicitando información de la base de datos. Por ejemplo, un inventario de productos. Tenga en cuenta que la solicitud del cliente no es una consulta SQL; es una llamada a procedimiento remoto como getInventoryList.
  3. El nivel de lógica de negocios se conecta a la base de datos y recupera la información solicitada. El nivel lógico de negocios se encarga de formar una consulta SQL segura en función de la solicitud del usuario. Todos los parámetros de la consulta SQL se deben desinfectar para evitar ataques de inyección SQL.
  4. El nivel lógico de negocios envía la lista de inventario a la aplicación cliente.
  5. El cliente muestra la lista de inventario al usuario.

Tenga en cuenta que en todo el proceso, la aplicación cliente nunca se conecta directamente a la base de datos. El nivel lógico empresarial recibe una solicitud de un usuario autenticado, procesa la solicitud del cliente para una lista de inventario y solo luego ejecuta una consulta SQL.

+4

¿Cómo esto impide que alguien obtenga el nombre de usuario/contraseña? ¿No puedes leerlo del archivo entonces? –

+0

Como dije en mi respuesta, si los permisos de sus archivos están configurados correctamente, solo el usuario que ejecuta el programa tiene acceso de lectura a ese archivo de preferencias. En entornos UNIX, esto se hace automáticamente. Windows puede requerir pasos adicionales (realmente no estoy seguro, ya que no uso mucho Windows). –

+0

Creo que la idea es que el usuario que ejecuta la aplicación no es el que está tratando de evitar. Si ese es el caso, entonces tendrías que encriptarlo. –

15

Ponga la contraseña en un archivo que la aplicación leerá. NUNCA incruste contraseñas en un archivo fuente. Período.

Ruby tiene un módulo poco conocido llamado DBI::DBRC para dicho uso. No tengo dudas de que Java tiene un equivalente. De todos modos, no es difícil escribir uno.

+5

Si bien eso hace que sea un poco más fácil cambiar las contraseñas más adelante, no resuelve el problema de seguridad básico. –

+0

Sí lo hace. Ver también la respuesta de William Brendel. – Keltia

+1

El método que Keltia y yo señalamos es la forma aceptada de tratar con este problema. Desacoplar sus credenciales de inicio de sesión de su código compilado es una de las prácticas de seguridad de software más básicas. Poner las credenciales de inicio de sesión en un archivo separado es una forma efectiva de lograr esto. –

3

¿Estás escribiendo una aplicación web? Si es así, use JNDI para configurarlo externamente a la aplicación. Una visión general está disponible here:

JNDI proporciona una manera uniforme para una aplicación de encontrar y acceder a distancia servicios a través de la red. El servicio remoto puede ser cualquier servicio de la empresa, incluyendo un servicio de mensajería o un servicio específico de la aplicación , pero, por supuesto , una aplicación JDBC es interesado principalmente en un servicio de base de datos. Una vez que un objeto DataSource se creado y registrado en un servicio de nombres JNDI , una aplicación puede utilizar la API JNDI para acceder a ese objeto DataSource , que luego se puede utilizar para conectarse a la fuente de datos que representa.

+0

si el enlace es malo –

0

MD5 es un algoritmo hash, no es un algoritmo de cifrado, en resumen, no puedes volver a obtener hashed, solo puedes compararlo. Idealmente, se debe utilizar al almacenar la información de autenticación de usuario y no el nombre de usuario y contraseña de db. db nombre de usuario y pwd se deben cifrar y mantener en un archivo de configuración, para hacer lo mínimo.

+0

He oído hablar de personas que generan todas las combinaciones posibles de cadenas y almacenan sus correspondientes hashes MD5. Entonces, cuando encuentran el hash MD5 de alguien, simplemente encuentran el hash que almacenaron y obtienen la cadena correspondiente. – Nav

1

Esta pregunta muestra cómo almacenar las contraseñas y otros datos en un archivo cifrado: Java 256-bit AES Password-Based Encryption

+0

En algún lugar del código fuente, todavía es necesario descifrar la contraseña cifrada para crear una conexión. Esta contraseña considerada todavía está allí. – Bear0x3f

1

No importa lo que hagas, la información sensible se almacenará en algún archivo en alguna parte. Tu objetivo es hacer que sea tan difícil de obtener como sea posible. La cantidad de esto que puede lograr depende de su proyecto, necesidades y grosor de la billetera de su empresa.

La mejor manera es no almacenar contraseñas en ninguna parte. Esto se logra mediante el uso de funciones hash para generar y almacenar la contraseña hashes:

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366 

algoritmos hash son función unidireccional. Convierten cualquier cantidad de datos en una "huella dactilar" de longitud fija que no se puede invertir. También tienen la propiedad de que si la entrada cambia aunque sea un poco, el hash resultante es completamente diferente (vea el ejemplo anterior). Este es ideal para proteger contraseñas, porque queremos guardar las contraseñas de una forma que las protege incluso si el archivo de contraseña en sí es comprometido, pero al mismo tiempo, necesitamos poder verificar que la contraseña de usuario es correcto.

nota no relacionada: En los viejos días de la Internet, al hacer clic en 'olvidado mi contraseña' enlace, los sitios web que se envíe su contraseña en texto plano. Probablemente estaban almacenando esos en una base de datos en alguna parte. Cuando los hackers obtengan acceso a su base de datos, obtendrán acceso a todas las contraseñas. Dado que muchos usuarios utilizarían la misma contraseña en varios sitios web, este fue un gran problema de seguridad. Afortunadamente, hoy en día esta no es una práctica común.

Ahora viene la pregunta: ¿cuál es la mejor manera de almacenar contraseñas?Yo consideraría solución this (authentication and user management service stormpath's) una muy muy ideales uno:

  1. Su usuario introduce las credenciales, y esto se valida con el hash contraseña se generan
  2. hashes de contraseñas y se almacena, no contraseñas se realizan
  3. Hashes varias veces
  4. hashes se generan usando una sal generada aleatoriamente
  5. Los valores hash se encriptan con una clave
  6. clave privada es privada st un OR en un lugar físicamente diferente de hashes
  7. Las claves privadas están en una forma basada en el tiempo actualizan
  8. hash cifrados se dividen en trozos
  9. Estos trozos se almacenan en físicamente lugares separados

Obviamente' no es el google o un banco, por lo que esta es una solución exagerada para usted. Pero luego viene la pregunta: ¿Cuánta seguridad requiere su proyecto, cuánto tiempo y dinero tiene?

Para muchas aplicaciones, aunque no se recomienda, almacenar una contraseña codificada en el código podría ser una solución lo suficientemente buena. Sin embargo, al agregar fácilmente algunos pasos adicionales de seguridad de la lista anterior, puede hacer que su aplicación sea mucho más segura.

Por ejemplo, supongamos que el paso 1 no es una solución aceptable para su proyecto. No desea que los usuarios ingresen la contraseña cada vez, o incluso no quiere/necesita que los usuarios conozcan la contraseña. Aún tienes información confidencial en algún lado y quieres proteger esto. Tiene una aplicación simple, no hay un servidor para almacenar sus archivos o esto es demasiado complicado para su proyecto. Su aplicación se ejecuta en entornos donde no es posible tener archivos almacenados de forma segura. Este es uno de los peores casos, pero aún con alguna medida de seguridad adicional puede tener una solución mucho más segura. Por ejemplo, puede almacenar la información confidencial en un archivo y puede encriptar el archivo. Puede tener la clave privada de cifrado codificada en el código. Puede ocultar el código, por lo que es un poco más difícil para alguien descifrarlo. Existen muchas bibliotecas para este propósito, vea this link. (Quiero advertirle una vez más que esto no es 100% seguro. Un pirata informático inteligente con el conocimiento y las herramientas correctas pueden piratear esto. Pero según sus requisitos y necesidades, esta podría ser una solución lo suficientemente buena para usted).

Cuestiones relacionadas