¿Cómo puedo proteger el nombre de usuario y la contraseña de MySQL de descompilarse?


Los archivos Java .class se pueden descompilar 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?

Author: Keith Pinson, 2009-01-14

6 answers

Nunca codifique contraseñas en su código. Esto se mencionó recientemente en el Top 25 Errores de programación más peligrosos :

Codificar una cuenta secreta y contraseña en su software es extremadamente conveniente -- para expertos ingeniería inversa. Si la contraseña es lo mismo en todo tu software, entonces cada cliente se vuelve vulnerable cuando esa contraseña se convierte inevitablemente conocido. Y porque está codificado, es un gran dolor fijar.

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 (nunca compilar en el binario para empezar).

Para obtener más información sobre este error común, puede leer el artículo CWE-259. 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 Preferences. Está diseñado para almacenar todo tipo de configuraciones del programa, algunas de las cuales podrían incluir un nombre de usuario y una 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, puede llamar al método setCredentials después de mostrar un diálogo askign para el nombre de usuario y la 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 serán codificado en sus binarios, por lo que la descompilación no representará un riesgo de seguridad.

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

Notas más importantes: Ha habido 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 realmente no menciona el contexto en el que se está utilizando la aplicación, por lo que hablaré sobre las dos situaciones que se me ocurren. El primero es el caso en el que la persona que utiliza el programa ya conoce (y está autorizada a conocer) la base de datos credencial. El segundo es el caso en el que usted, el desarrollador, está tratando de mantener las credenciales de la base de datos en secreto de la persona que utiliza el programa.

Primer caso: El usuario está autorizado a conocer las credenciales de inicio de sesión de la base de datos

En este caso, la solución que mencioné 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 las preferencias XML y leer las credenciales de inicio de sesión, pero eso no es un riesgo de seguridad porque el usuario conocía las credenciales para empezar.

Segundo caso: Intentar ocultar las credenciales de inicio de sesión del usuario

Este es el caso más complicado: el usuario no debe conocer las credenciales de inicio de sesión, pero aún necesita 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 conocer las credenciales de inicio de sesión antes de tiempo. La solución que mencioné anteriormente 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 utilizar este caso de una manera segura.

Caso correcto: Usando una arquitectura de varios niveles

La forma correcta de hacerlo es tener una capa intermedia, entre su servidor de base de datos y su aplicación cliente, que autentique usuarios individuales y permite realizar un conjunto limitado de operaciones. Cada usuario tendría sus propias credenciales de inicio de sesión, pero no para el servidor de base de datos. Las credenciales permitirían el acceso a la capa intermedia (el nivel de lógica de negocio) 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 una arquitectura de tres niveles (los niveles son su servidor de base de datos, servidor de lógica empresarial y aplicación 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. El cliente se autentica con el nivel de lógica de negocio utilizando el nombre de usuario/contraseña personal 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 a la nivel de lógica de negocio que pide cierta 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 un procedimiento remoto como getInventoryList.
  3. El nivel de lógica de negocio se conecta a la base de datos y recupera la información solicitada. El nivel de lógica empresarial se encarga de formar una consulta SQL segura basada en la solicitud del usuario. Cualquier parámetro de la consulta SQL debe ser desinfectado para evitar la inyección SQL ataques.
  4. El nivel de lógica de negocio 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 de lógica de negocio recibe una solicitud de un usuario autenticado, procesa la solicitud del cliente para una lista de inventario y solo entonces ejecuta una consulta SQL.

 109
Author: William Brendel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-18 08:02:21

Coloque la contraseña en un archivo que la aplicación leerá. NUNCA incruste contraseñas en un archivo de origen. Periodo.

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

 15
Author: Keltia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-08 07:22:45

Estás escribiendo una aplicación web? Si es así, use JNDI para configurarlo externamente a la aplicación. Un resumen está disponible aquí :

JNDI proporciona una forma uniforme para un aplicación para buscar y acceder a distancia servicios a través de la red. Remoto el servicio puede ser cualquier servicio empresarial, incluyendo un servicio de mensajería o un servicio específico de aplicación, pero de por supuesto, una aplicación JDBC es interesado principalmente en una base de datos Servicio. Una vez que un DataSource el objeto es creado y registrado con un JNDI servicio de nombres, una aplicación puede utilizar la API JNDI para acceder a esa fuente de datos objeto, que luego se puede utilizar para conéctese a la fuente de datos representar.

 3
Author: Tim Howland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-14 13:28:15

No importa lo que haga, la información confidencial se almacenará en algún archivo en algún lugar. Su objetivo es hacer que sea tan difícil de conseguir como sea posible. Cuánto de esto puede lograr depende de su proyecto, necesidades y grosor de la cartera de su empresa.

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

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

Los algoritmos Hash son funciones unidireccionales. Convierten cualquier cantidad de datos en una "huella digital" de longitud fija que no se puede revertir. También tienen la propiedad de que si la entrada cambia incluso un poco, el hash resultante es completamente diferente (ver el ejemplo anterior). Este es ideal para proteger contraseñas, porque queremos almacenar contraseñas en una forma que los protege incluso si el archivo de contraseña en sí es comprometido, pero al mismo tiempo, tenemos que ser capaces de verificar que un la contraseña del usuario es correcta.

no Relacionados nota: En los viejos tiempos de Internet, cuando haces clic en el enlace "olvidé mi contraseña", los sitios web te enviaban por correo electrónico tu contraseña de texto sin formato. Probablemente los estaban almacenando en una base de datos en alguna parte. Cuando los hackers obtenían acceso a su base de datos, obtenían acceso a todas las contraseñas. Dado que muchos usuarios usarían la misma contraseña en varios sitios web, este fue un gran problema de seguridad. Afortunadamente, hoy en día esta no es la práctica común.

Ahora viene la pregunta: ¿qué es lo mejor ¿cómo almacenar contraseñas? Consideraría esta solución (autenticación y administración de usuarios del servicio stormpath) una solución bastante ideal:

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

Obviamente no eres Google o un banco, así que esta es una solución exagerada para ti. Pero luego viene la pregunta: ¿Cuánta seguridad requiere su proyecto, cuánto tiempo y dinero tiene?

Para muchos aplicaciones, aunque no se recomienda, almacenar una contraseña codificada en el código podría ser una buena solución. Sin embargo, al agregar fácilmente un par de 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 quieres que los usuarios ingresen la contraseña cada vez, o ni siquiera quieres / necesitas que los usuarios conozcan la contraseña. Todavía tienes información sensible en algún lugar y quiero 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 cifrarlo. Puede tener la clave privada de cifrado codificada en el codificar. Puedes ofuscar el código, para que sea un poco más difícil para alguien descifrarlo. Existen muchas bibliotecas para este propósito, ver este enlace. (Quiero advertirle una vez más que esto no es 100% seguro. Un hacker inteligente con el conocimiento y las herramientas adecuadas puede hackear esto. Pero basado en sus requisitos y necesidades, esto podría ser una solución lo suficientemente buena para usted).

 2
Author: Caner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-19 11:48:02

Esta pregunta muestra cómo almacenar contraseñas y otros datos en un archivo cifrado: Cifrado basado en contraseñas Java AES de 256 bits

 1
Author: Aaron Digulla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:04

MD5 es un algoritmo hash, no un algoritmo de cifrado, en resumen u no puede volver wat u hashed, u solo puede comparar. Idealmente, debería usarse cuando se almacena la información de autenticación del usuario y no el nombre de usuario y la contraseña de la base de datos. el nombre de usuario de la base de datos y el pwd deben cifrarse y mantenerse en un archivo de configuración, por lo menos.

 0
Author: renegadeMind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-14 13:55:50