2009-05-07 18 views
7

Tengo una aplicación de cliente WPF interna que accede a una base de datos.A Dificultad de seguridad (cifrado)

La aplicación es un recurso central para un equipo de soporte y, como tal, incluye acceso remoto/información de inicio de sesión para los clientes. Por el momento, esta base de datos no está disponible a través de una interfaz web, etc., pero es probable que algún día lo haga.

La información de acceso remoto incluye el nombre de usuario y las contraseñas para las redes del cliente para que las aplicaciones de software de nuestro cliente puedan ser remotamente admitidas por nosotros. Necesito almacenar los nombres de usuario y las contraseñas en la base de datos y proporcionar a los consultores de soporte el acceso a ellos para que puedan iniciar sesión en el sistema del cliente y luego brindar asistencia. Espero que esto tenga sentido.

Así que el dilema es que no quiero almacenar los nombres de usuario y contraseñas en texto plano en la base de datos para asegurar que si el DB se vio comprometido, no estoy proporcionando acceso a las redes de nuestros clientes a quien obtenga la base de datos .

He examinado el cifrado bidireccional de las contraseñas, pero como se dice, bidireccional no es muy diferente de texto claro como si pudieras descifrarlo, también un atacante ... eventualmente. El problema aquí es que he configurado un método para usar una sal y un código de acceso que están almacenados en la aplicación, he usado una sal que está almacenada en el archivo db, pero todos tienen sus puntos débiles, es decir, si la aplicación se refleja, expone las sales, etc.

¿Cómo puedo proteger los nombres de usuario y las contraseñas en mi base de datos, y todavía puedo permitir a mis consultores de soporte ver la información en la aplicación para que puedan usarla para iniciar sesión?

Esto es obviamente diferente al almacenamiento de las contraseñas del usuario, ya que son de una sola manera, ya que no necesito saber cuáles son. Pero sí necesito saber cuáles son las contraseñas de acceso remoto del cliente, ya que necesitamos ingresarlas en el momento de la comunicación remota.

¿Alguien tiene algunas teorías sobre cuál sería el mejor enfoque aquí?

actualización La función que intento crear es para nuestra aplicación CRM que almacenará los detalles de acceso remoto para el cliente. El sistema CRM proporciona funcionalidad de seguimiento de llamadas/problemas y durante el curso de la investigación del problema, el consultor de soporte deberá ingresar de manera remota. Luego verán los detalles de acceso remoto del cliente y harán la conexión

+0

¿Los detalles de la cuenta tienen privilegios administrativos en las redes de sus clientes? He tratado con una empresa que suministró y apoyó nuestro servidor de forma remota. Aunque tenían acceso remoto, solicitaron la contraseña de administrador cada vez que los llamé. – stukelly

+0

Travis, lea mi respuesta a sus comentarios sobre mi respuesta. (Solo escribo este comentario porque el problema es grave y no sé si StackOverflow le notificará mi respuesta) –

Respuesta

4

Ocurre una situación similar en nuestra empresa, donde los administradores de la base de datos desean mantener un conjunto de credenciales entre ellos.

Originalmente iba a publicar esta idea, pero erickson beat me to it. Sin embargo, puede ser vale la pena publicar algunos pseudo código para la elaboración, así que supongo que mi tiempo respondiendo a la pregunta no está completamente perdido ...

Cosas que necesitará:

En primer lugar, vamos a configurar el esquema de base de datos. Estas tablas se demostrarán en breve.

CREATE TABLE users (
    user_id    INTEGER, 
    authentication_hash BINARY, 
    authentication_salt BINARY, 
    public_key   BINARY, 
    encrypted_private_key BINARY, 
    decryption_key_salt BINARY, 
    PRIMARY KEY(user_id) 
) 

CREATE TABLE secrets (
    secret_id INTEGER, 
    -- WHATEVER COLUMNS YOU REQUIRE TO ACCURATELY MODEL YOUR PASSWORDS (CLIENT INFO, ETC) 
    PRIMARY KEY(secret_id) 
) 

CREATE TABLE granted_secrets (
    secret_id  INTEGER, 
    recipient_id INTEGER, 
    encrypted_data BINARY, 
    PRIMARY KEY(secret_id, recipient_id), 
    FOREIGN KEY(secret_id) REFERENCES secrets(secret_id) 
    FOREIGN KEY(recipient_id) REFERENCES users(user_id) 
) 

Antes de que un usuario pueda comenzar a usar este sistema, debe estar registrado.

function register_user(user_id, user_password) { 
    authentication_salt = generate_random_salt() 
    authentication_hash = hash(authentication_salt, user_password); 

    (public_key, private_key) = asymmetric_cipher_generate_random_key_pair(); 

    decryption_key_salt = generate_random_salt() 
    decryption_key = derive_key(decryption_key_salt, user_password) 
    encrypted_private_key = symmetric_cipher_encrypt(
     input => private_key, 
     key => decryption_key 
    ) 

    // IMPORTANT: The decryption_key_hash is never stored 

    execute("INSERT INTO users (user_id, authentication_hash, authentication_salt, public_key, encrypted_private_key, decryption_key_salt) VALUES (:user_id, :authentication_hash, :authentication_salt, :public_key, :encrypted_private_key, :decryption_key_salt)") 
} 

El usuario puede iniciar sesión en el sistema.

function authenticate_user(user_id, user_password) 
    correct_authentication_hash = query("SELECT authentication_hash FROM users WHERE user_id = :user_id") 

    authentication_salt = query("SELECT authentication_salt FROM users WHERE user_id = :user_id") 
    given_authentication_hash = hash(authentication_salt, user_password) 

    return correct_authentication_hash == given_authentication_hash 

A continuación, se puede otorgar un secreto a un usuario destinatario.

function grant_secret(secret_id, secret_data, recipient_id) { 
    recipient_public_key = query("SELECT public_key FROM users WHERE user_id = :recipient_id") 

    encrypted_secret_data = asymmetric_cipher_encrypt(
     input  => secret_data, 
     public_key => recipient_public_key 
    ) 

    execute("INSERT INTO granted_secrets (secret_id, recipient_id, encrypted_data) VALUES (:secret_id, :recipient_id, :encrypted_secret_data)") 
} 

Finalmente, un usuario que ha recibido acceso a un secreto (el destinatario) puede recuperarlo.

void retrieve_secret(secret_id, recipient_id, recipient_password) 
    encrypted_recipient_private_key = query("SELECT encrypted_private_key FROM users WHERE user_id = :recipient_id") 

    recipient_decryption_key_salt = query("SELECT decryption_key_salt FROM users WHERE user_id = :recipient_id") 
    recipient_decryption_key = derive_key(recipient_decryption_key_salt, recipient_password) 
    recipient_private_key = symmetric_cipher_decrypt(
     input => encrypted_recipient_private_key, 
     key => recipient_decryption_key 
    ) 

    encrypted_secret_data = query("SELECT encrypted_data FROM granted_secrets WHERE secret_id = :secret_id AND recipient_id = :recipient_id") 

    secret_data = asymmetric_cipher_decrypt(
     input  => encrypted_secret_data, 
     private_key => recipient_private_key 
    ) 

    return secret_data 

Espero que esto te pueda ayudar. Ciertamente me ayudó a dar cuerpo a mis ideas.

+0

Adam, gracias por el código de ejemplo. Estaba luchando un poco por entender los conceptos de Erickson, no por lo que él estaba discutiendo, sino por cómo 'hacerlo realidad'. Sus ejemplos definitivamente han ayudado a aclarar el concepto. – TravisPUK

+0

De hecho, ya tengo las contraseñas del usuario almacenadas en una tabla de usuario, junto con sus sales asociadas también en una tabla de usuario. – TravisPUK

+1

@ TravisPUK: Travis, modifiqué mi respuesta para acomodar tu hash. El hash utilizado para descifrar la clave privada de un usuario NO DEBE ALMACENAR. De lo contrario, cualquiera que tenga acceso a la base de datos ahora puede descifrar los secretos de cualquier usuario. La respuesta modificada distingue entre el hash utilizado para autenticar a un usuario y el hash utilizado para descifrar su clave privada. –

0

Si necesita recuperar el borrar la contraseña de texto de la base de datos, entonces necesitará usar un esquema de cifrado bidireccional.

No coloque la clave en su aplicación cliente.

De esta forma puede volver a cifrar los datos/cambiar la clave con regularidad si le preocupa que la clave se vea comprometida. Aunque si su clave es lo suficientemente fuerte y no está disponible públicamente, debe estar seguro

Al enviar las contraseñas a través de una conexión de red, asegúrese de usar SSL para encriptar el enlace.

La configuración podría tener este cliente

---> servidor ---> DB

El servidor descifra la contraseña y se lo pasa a través del enlace SSL para el cliente.

Si no tiene un servidor y sus clientes se conectan directamente a un DB, puede hacer que su cliente llame a un procedimiento almacenado para recuperar la contraseña de texto sin formato.

0

Esto suena como un escenario DPAPI fue diseñado para. Cree un nivel intermedio que pueda autenticar a sus clientes, y luego use DPAPI para cifrar datos antes de almacenarlos en el DB

-3

No necesita mantener sus contraseñas en la base de datos, solo mantenga un hash de ellas (SHA1 como ejemplo) Luego, al momento de iniciar sesión, simplemente calcule el hash nuevamente y compárelo con el hash ordenado.

Créanme, si no tienen contraseñas almacenadas, se les quitará mucho peso de los hombros.

+0

Excelente consejo si almacena contraseñas para que otras personas puedan iniciar sesión en su sistema. Sin embargo, se trata de almacenar contraseñas para que las personas de su sistema puedan iniciar sesión en otras y, por lo tanto, la contraseña debe almacenarse. –

+0

barra diagonal inversa, lo que está describiendo está en uso para las contraseñas del usuario, donde no es necesario que revierte la contraseña. Estoy buscando almacenar las contraseñas de forma segura y luego ser capaz de descifrarlas para que las vea el personal o enviarlas a un servicio de terceros (es decir, gmail) a través de SSL, etc. – TravisPUK

+0

Lamento no haber leído toda la pregunta. ¡Mi culpa! – backslash17

2

Almacene sus contraseñas encriptadas con AES y una buena llave fuerte. En lugar de incrustar la clave de descifrado en la aplicación, entréguesela a sus usuarios (los consultores de soporte). Luego haga que su aplicación los solicite cuando necesiten buscar la información. No es ideal, porque todos usan la misma clave, pero al menos ofrece algo de protección si alguna vez se compromete su base de datos.

+0

Jason, definitivamente me gusta la idea de tener las llaves con los consultores. – TravisPUK

6

Hay algunas formas de hacerlo; la mejor solución dependerá de cómo su equipo de soporte acceda a los sitios de los clientes, cuántos miembros pertenecen al equipo de soporte y la arquitectura de su aplicación.

La mejor manera de hacer algo como esto es usar algo como Kerberos. De esta forma, los miembros del equipo de soporte no tienen que confiar las contraseñas — de las contraseñas de los clientes que podrían anotar y usar posteriormente para atacar a los clientes. El equipo de soporte puede revocar instantáneamente el acceso del miembro sin ninguna acción del cliente.

Sin embargo, supongo que este es un sistema más peligroso en el que los miembros del equipo obtienen una contraseña para acceder a los sistemas cliente a través de Escritorio remoto, SSH o algo así. En ese caso, se asume una gran responsabilidad cuando las contraseñas de los clientes se revelan a los miembros del equipo.

Personalmente, no aceptaría ese tipo de riesgo. No es que no sienta que puedo confiar en mi equipo, sino que no puedo confiar en mis clientes. Si algo sucede en su sitio (o incluso si simplemente pretenden que algo sucedió), de repente soy sospechoso. Prefiero diseñar un sistema donde nadie pueda acceder a los sistemas del cliente actuando solo. Esto protege al cliente de una mala manzana en mi equipo y me protege de falsas acusaciones.

De todos modos, un enfoque sería generar claves para cada miembro del equipo. Estas podrían ser claves de cifrado simétricas basadas en contraseña, pero algunas claves secretas deben mantenerse centralizadas. Mejor sería usar un algoritmo asimétrico como RSA. Entonces solo las claves públicas de los miembros del equipo se mantienen centralmente.

Cuando se recibe una nueva contraseña de un cliente, encripte con la clave pública de cada miembro del equipo que necesite una copia. Esta contraseña encriptada puede almacenarse en la base de datos y entregarse a un miembro del equipo cada vez que la solicite, o puede enviarse activamente a los miembros del equipo para que la almacenen. En cualquier caso, cuando sea necesario, la contraseña se descifra con la clave privada en poder del miembro del equipo (en un almacén de claves cifrado con la contraseña que elija).

Hay desventajas en esto. Reiterando el punto anterior, los miembros del equipo obtienen acceso a la contraseña de los clientes. ¿Son dignos de esta confianza? ¿Qué pasa si el cliente tiene una violación de seguridad no relacionada con este sistema, pero quiere echarle la culpa a alguien? En segundo lugar, aunque no se almacenan claves de descifrado en el servidor, aún se necesita establecer la confianza para la clave pública de cada miembro del equipo.De lo contrario, un atacante podría deslizar su propia clave pública deshonesta en la colección y recibir contraseñas que pueden descifrar.

+0

+1. Excelente respuesta Su esquema de encriptación de contraseñas es inquietantemente similar a lo que estaba a punto de publicar ... –

+1

Uso el software de acceso remoto, donde el cliente debe iniciar la conexión a su computadora. Luego pueden monitorear mi progreso durante una llamada. – stukelly

+0

El software de acceso remoto varía, algunos clientes simplemente tendrán una conexión VNC, algunos tendrán VPN mucho más sofisticadas que usen generadores de claves RSA, etc. Normalmente se reducirá al conocimiento y presupuesto del cliente. Para que quede claro, simplemente le pedimos al cliente que proporcione acceso remoto a su aplicación/servidor de base de datos para que podamos respaldar remotamente nuestros productos de software para ellos. – TravisPUK

1

Si le preocupa dar la contraseña de usuario original a los consultores, entonces aquí hay algo que pensar.

¿Qué ocurre al generar una contraseña/token temporal exclusivamente para su miembro de soporte?

Cuando un cliente hace una llamada, crea un token y colócalo en un mapa junto con el ID de usuario. Envíe este token o token encriptado a su miembro de atención al cliente. El miembro de soporte al cliente iniciará sesión usando el nombre de usuario y el token. Comprobación del sistema para el token en el mapa válido a la vista y encuentra que es un token válido y otorga acceso al sistema.

Support memeber soluciona el problema. Luego el token se elimina de tokenMap.

De esta forma, nunca revelará la contraseña de usuario original a los consultores. Así puede almacenar las contraseñas de usuario usando sus propias técnicas de seguridad preferidas.

Puede cifrar el token utilizando la clave pública del asesor antes de enviarlo.

Los tokens pueden tener vencimiento.

+0

@kevin, gracias por su respuesta. Al igual que la idea que está presentando, sin embargo, no tenemos el control del nombre de usuario y las contraseñas que nos ha proporcionado el cliente, ni del software preferido del cliente. Los consultores realmente necesitan tener el nombre de usuario y la contraseña del cliente a distancia en lugar de uno personalizado para la sesión. – TravisPUK

Cuestiones relacionadas