c# - Manejo seguro de claves privadas desde Windows Key Store
security cryptography (4)
¿Alguien tiene alguna sugerencia sobre cómo puedo hacer que mi modelo sea más seguro?
Tiene razón en que cualquier servicio que se ejecute en Servicios de red comprometidos podría tener acceso a la clave privada. En algún momento de 2005, Microsoft se dio cuenta y comenzó a crear cuentas de servicio únicas para limitar el daño causado por un servicio comprometido común , como los servicios de red . Por ejemplo, el servidor SQL se movió a su propia cuenta de servicio, IIRC.
El problema subyacente es un problema de diseño de seguridad con el modelo de Microsoft, y no hay mucho que pueda hacer con él. Microsoft se dio cuenta y se mudó a un modelo ligeramente diferente con CryptoNG, IIRC. Bajo CryptoNG, las operaciones que utilizan la clave privada están fuera de proceso y el IPC se usa para comunicar solicitudes y resultados entre el servicio y el proceso que realiza operaciones clave. En su mayoría, esto acelera el problema que le preocupa.
Incluso con el nuevo modelo, aún necesitará un software que conozca el modelo. Debería estar bien con, digamos, IIS 7, pero Apache puede causar problemas porque su modelo solo reconoce las ACL del sistema de archivos.
Mover las operaciones clave fuera del proceso se está convirtiendo en una práctica estándar. Por ejemplo, GnuPG hace lo mismo. GnuPG utiliza una biblioteca llamada libassuan que realiza la clasificación de solicitudes y resultados entre consumidores y productores.
No me preocuparía demasiado sobre las preocupaciones de eficiencia entre el cliente y el servidor en el modelo fuera de proceso. Windows Pipes, Unix Pipes y Unix Domain Sockets se están aligerando rápidamente. Además, es muy parecido al Dr. Jon Bentley, dijo: Si no tiene que ser correcto, puedo hacerlo tan rápido como te gustaría.
Estoy trabajando en una aplicación que cifra la configuración del archivo de configuración para un servidor web ASP.Net. El método de encriptación que estoy implementando está envolviendo datos usando AES y RSA. Estoy generando una clave AES, usando esa clave AES para encriptar mis datos, luego encriptando la clave AES con la clave pública de un certificado en mi Tienda de certificados de Windows. Luego guardo los datos, junto con la clave AES encriptada, y el número de serie del certificado utilizado para encriptarlo, de vuelta al archivo de configuración.
Cuando quiero acceder a estos datos, leo el número de serie del certificado utilizado para encriptar la clave AES, saco la clave privada de ese certificado y descifro la clave AES, luego descifro los datos usando esa clave. Aquí es donde no estoy seguro de mi nivel de seguridad.
Para acceder a la clave privada asociada con el certificado, debo marcar la clave privada como exportable y darle al usuario que mi aplicación se ejecuta con acceso a la clave privada. Como este es un servidor ASP.Net, ese usuario es "Servicios de red". Estoy seguro de que puede ver por qué esto sería un problema de seguridad. Básicamente, si alguien entrara en mi servidor ASP.Net a través de la web, quizás mediante algún tipo de inyección, tendrían acceso a esa clave privada, ¿no es así?
¿Alguien tiene alguna sugerencia sobre cómo puedo hacer que mi modelo sea más seguro?
Descifrar la función:
//need an rsa crytpo provider to decrypt the aes key with the private key associated with the certificate
using (RSACryptoServiceProvider rsaCSP = (RSACryptoServiceProvider) decryptionCertificate.PrivateKey)
{
//decrypt the aes key with the cert''s private key
byte[] aesKey = rsaCSP.Decrypt(encryptedAESKey, false);
//decrypt data using the decrypted aes key and the IV passed in
decryptedData = decryptWithAes(encryptedData, aesKey, aesIV);
}
Gracias.
Creo que hay algunos conflictos inherentes con su modelo de seguridad. Desea que una aplicación que se ejecuta bajo el usuario "Servicios de red" pueda descifrar el archivo de configuración, pero desea que la información cifrada sea segura incluso si el usuario de "Servicios de red" está en peligro. Esos dos objetivos están en desacuerdo: o el usuario puede acceder a los datos o no puede. Creo que lo mejor que puede hacer es aislar el acceso de seguridad, de modo que si "Servicios de red" en una máquina se ve comprometido, no ponga en peligro la seguridad de otros usuarios u otras máquinas. Es por eso que el modelo de seguridad de Windows proporciona a cada usuario en cada máquina su propia clave privada, y esa es la clave utilizada por DPAPI para cifrar / descifrar los archivos de configuración.
Usted dice que en su modelo está encriptando la información de configuración con un conjunto estándar de claves. En este modelo, si un usuario de confianza en una máquina está en peligro, el atacante obtiene la clave para acceder a todos los datos de configuración cifrados para todos los usuarios en todas las máquinas. Usted dice que está utilizando claves administradas en caso de falla de la máquina. Sugeriría que es más seguro hacer una copia de seguridad y administrar los DATOS que se encriptan, luego hacer una copia de seguridad y administrar las LLAVES que se usan para acceder a esos datos.
Mi sugerencia es usar los métodos .Net integrados para cifrar / descifrar los datos de configuración, que usa la clave privada de Windows del usuario en la máquina local. (hay algunos ejemplos de implementación del enfoque estándar aquí: http://weblogs.asp.net/jgalloway/archive/2008/04/13/encrypting-passwords-in-a-net-app-config-file.aspx y aquí : http://www.codeproject.com/KB/security/ProtectedConfigWinApps.aspx ) Si se están poniendo datos en los archivos de configuración que son esenciales y tendrían que recuperarse en caso de falla de la máquina, envíe esos datos a su base de datos u otro almacén de datos central como una copia de seguridad. Esto evita usar la misma clave administrada o claves para todas sus implementaciones.
Si tiene un certificado con una clave privada, tiene sentido utilizar el cifrado PKCS # 7 / CMS de la clave AES. Esto le permite descifrar los datos con claves privadas no exportables.
Desafortunadamente, .NET no parece ofrecer clases para el cifrado CMS. CryptoAPI ofrece tales funciones ( CryptEncryptMessage y CryptDecryptMessage ), pero necesitan ser llamadas a través de P / Invoke, que en cierta medida puede ser no trivial. Para la muestra C # de hacer esto, vea el código fuente aquí .
Una opción alternativa sería usar nuestros componentes SecureBlackbox (TElMessageEncryptor, TElMessageDecryptor), aunque en su caso esto podría ser una exageración.
Solo escribiendo
RSACryptoServiceProvider rsaCSP = (RSACryptoServiceProvider)decryptionCertificate.PrivateKey
no significa que está asignando la "clave" real. Puede hacer que la clave privada no sea exportable y aún así poder realizar el descifrado.