ponen - estandar de documentacion de codigo c#
¿Cuál es la mejor manera de proteger los datos confidenciales en el código? (7)
Estaba examinando las formas de proteger mi código de la descompilación.
Hay varios subprocesos buenos que describen la ofuscación y el empaquetado de código como las posibles formas de proteger el código. Sin embargo, ninguno de ellos es ideal, la ofuscación no funciona con la reflexión cuando se utilizan los nombres de propiedad / método de cadena. Muchas personas no recomiendan utilizar la ofuscación en absoluto.
Así que actualmente decidí no seguir ninguno de los anteriores. Sin embargo , tengo partes del código donde necesito una especie de cifrado , por ejemplo, una cadena de conexión de base de datos con una IP, el inicio de sesión y la contraseña se almacenan dentro del código como una const string
, igual que los datos de la cuenta de correo electrónico.
En ASP.NET hay una opción para mover los datos confidenciales a un archivo .config
y cifrarlos, pero eso requiere la clave del servidor, es decir, está vinculada a una sola computadora. No leí mucho al respecto, pero supongo que hay algo similar disponible para las aplicaciones de escritorio. Pero necesito esto para trabajar en cualquier computadora donde esté instalada la aplicación.
Y aquí está la pregunta: ¿hay formas de codificar / proteger dichos datos para que no puedan leerse junto con el código descompilado?
Como Lucas señaló en su comentario, si solo tiene una pieza, cualquiera que descomponga su aplicación puede realizar ingeniería inversa y descifrar las contraseñas de su base de datos.
Acerca del almacenamiento de credenciales, mi práctica habitual es almacenarlas siempre en el archivo de configuración de la aplicación. Si luego necesito asegurarlo, uso un SecureString y algo de encriptación. Y esto podría funcionar para cualquier tipo de información de configuración, no solo para credenciales. Hay un artículo realmente bueno sobre cómo proteger los archivos de configuración aquí: Cifrar contraseñas en un archivo .NET app.config
El primer consejo es nunca almacenar nada sensible en su código directamente. Siempre puede realizar ingeniería inversa de eso, sin importar qué tan ingeniosamente intente ofuscarlo.
He leído sobre cosas como dividir una contraseña en varias partes, colocarlas en diferentes lugares en el código y ejecutarlas a través de una serie de funciones antes de finalmente usarlas ... aunque esto hace las cosas más difíciles, aún puede monitorear la aplicación. utilizando un depurador y, en última instancia, podrá recuperar la información secreta.
Si interpreto su escenario correctamente, lo que tiene es un código que se implementará en las instalaciones de algunos clientes y su código está conectado a una base de datos (que supongo que también está bajo la supervisión del cliente), para conectarse se requiere una contraseña. El cliente conoce esta contraseña, por lo que intentar ocultarla del cliente es bastante inútil. Lo que sí quiere es restringir el acceso a esa contraseña de cualquier persona que se supone que no debe saberlo.
Por lo general, esto se logra al colocar la información confidencial en un archivo separado en una carpeta que debería tener permisos muy restrictivos, solo la aplicación y un puñado de personas seleccionadas deberían tener acceso. La aplicación podría acceder a la información cuando sea necesario durante el tiempo de ejecución.
Además, cifrar el archivo separado resulta ser un problema. Si lo hace, entonces hay una clave involucrada que, de nuevo, debería estar protegida de alguna manera. La recursión infinita está en camino :) Asegurar el acceso al archivo a menudo es suficiente, pero si realmente necesita estar lo más seguro posible, entonces una solución es utilizar el cifrado basado en contraseña para el archivo. Pero la idea aquí no es almacenar la contraseña en otra ubicación del sistema, sino más bien como información fuera de banda (por ejemplo, en una bóveda física) e ingresar la contraseña al iniciar la aplicación. Esto también tiene sus problemas: la presencia física de una persona es necesaria para (re) iniciar la aplicación, y aún podría recuperar la contraseña de la memoria RAM de la máquina en la que se está ejecutando la aplicación. Pero es probablemente lo mejor que puedes hacer sin hardware especializado.
Otra buena alternativa al cifrado basado en contraseñas sería confiar en "bóvedas de contraseñas" específicas del sistema operativo, como el almacenamiento aislado de Windows, es una especie de compromiso entre no cifrar en absoluto y mantener la contraseña fuera de banda.
Esta no es una respuesta de cifrado, pero una forma de "asegurar" sería hacer todas las llamadas de su base de datos a través de un servicio web. Sus credenciales de conexión se almacenarán en su servidor seguro y los clientes pasarán todas las llamadas allí.
Nada sensible almacenado en su redistribuible en absoluto ...
Existen muchos métodos, pero la realidad es que si realmente desea proteger su código, la única solución es utilizar productos "profesionales" :-) no intente reinventar la rueda. Estos productos normalmente tienen opciones para cifrar cadenas. El problema real es otro: sin un producto profesional (e incluso CON un producto profesional), un experto puede simplemente poner un punto de interrupción y observar los parámetros pasados al método de la biblioteca (por ejemplo, el que abre las conexiones). Ahora ... Si realmente quieres encriptar las cadenas de tu código, es bastante fácil. ¿Pero sería útil? No.
Ahora, solo para que nadie marque esto como "no es una respuesta", publicaré un código simple de cifrado / descifrado:
// Generate key. You do it once and save the key in the code
var encryptorForGenerateKey = Aes.Create();
encryptorForGenerateKey.BlockSize = 128;
encryptorForGenerateKey.KeySize = 128;
encryptorForGenerateKey.GenerateKey();
encryptorForGenerateKey.GenerateIV();
var key = encryptorForGenerateKey.Key;
var iv = encryptorForGenerateKey.IV;
// Encrypt: this code doesn''t need to be in the program. You create a console
// program to do it
var encryptor = Aes.Create();
var encryptorTransformer = encryptorForGenerateKey.CreateEncryptor(key, iv);
string str = "Hello world";
var bytes = Encoding.UTF8.GetBytes(str);
var encrypted = encryptorTransformer.TransformFinalBlock(bytes, 0, bytes.Length);
var encryptedString = Convert.ToBase64String(encrypted);
Console.WriteLine(encryptedString);
// Decrypt: this code needs to be in the program
var decryptor = Aes.Create();
var decryptorTransformer = decryptor.CreateDecryptor(key, iv);
byte[] encrypted2 = Convert.FromBase64String(encryptedString)
var result = decryptorTransformer.TransformFinalBlock(encrypted2, 0, encrypted2.Length);
var str2 = Encoding.UTF8.GetString(result);
Este código claramente no es seguro. Cualquiera puede descompilar el programa, agregar una Console.WriteLine(str2)
y recompilarlo.
He lidiado con este problema en el pasado y he encontrado tres formas de resolverlo, pero no estoy seguro de que alguna de ellas sea perfecta:
- Ofuscar o encriptar el valor y esperar lo mejor. El cifrado, por supuesto, es solo un nivel adicional de ofuscación, ya que la clave debe entregarse con el resto.
- Elimine la necesidad de la clave en sí misma mediante el uso de cifrado unidireccional. Utilice una clave privada para generar una clave pública. Esto se puede utilizar para la licencia o la validación de la contraseña. Genera las licencias con la clave privada, pero la clave pública puede usarse para validarlas. O utiliza la clave privada para generar una contraseña que se puede validar, pero no se puede revertir con la clave pública.
- Cree su propio mecanismo de generación de claves específico del sistema similar al utilizado por ASP.NET. Puede limitar el efecto de que alguien revierta el cifrado / ofuscación en el paso 1 generando una clave única para cada instalación o sitio.
Por supuesto, puede cifrar su cadena antes de compilarla, pero su código necesita eso en texto sin formato en algún momento si está utilizando una base de datos simple o http url.
No hay una protección real en este caso: todos pueden escuchar (punto de interrupción) un método específico y, cuando se les llama, ver qué está pasando sin leer realmente su código. Así que no, no hay una protección real contra esto, también utilizando la ofuscación en algún momento al que llamarás algún método .NET con esa cadena de texto sin formato, y todos pueden leerlo.
Por ejemplo, puede poner un DLL COM o C ++ para almacenar cadenas cifradas. Una dll no administrada no es descompilable, sin embargo, las personas expertas pueden comprender el desmontaje de una dll. Y como se dijo antes, en algún momento necesitará los datos simples, y en ese momento, no hay protección que pueda durar.
Lo único que puedes hacer es cambiar tu arquitectura.
Por ejemplo, si su base de datos está en línea y su aplicación es una aplicación cliente, puede conectarse utilizando servicios web. Entonces puede exponer solo los servicios web que el usuario realmente necesita usar, no hay riesgo de que el usuario escriba consultas de SQL. Luego puede agregar la lógica de protección en el servidor en lugar de en el cliente.
Si todo está desconectado, no hay mucho que puedas hacer, puedes hacer la vida más difícil con el simple cifrado de cadenas, pero nunca será una verdadera protección.
Tal vez debería leer algo más sobre el cifrado de web.config http://learn.iis.net/page.aspx/141/using-encryption-to-protect-passwords/
De lo contrario no hay mucho que puedas hacer. El almacenamiento de datos confidenciales en el código no es una opción, ya que cualquier persona con una herramienta reflectora puede abrirla y verla. Si desea que el código o las variables sean invisibles para todos, debe crear un servicio web en un servidor privado que acepte datos, los transforme a través de su magia y los devuelva al cliente. De esa manera, todo lo que se encuentra entre la publicación y la recuperación de los datos se mantiene en secreto.