Encriptación de valores en la configuración (app.config)

4,738 views
Skip to first unread message

Kiquenet

unread,
Sep 13, 2011, 5:47:06 PM9/13/11
to altnet-...@googlegroups.com

Por regla general, en un fichero App.Config, podemos encontrar dos secciones predefinidas, que son las que se usan habitualmente en los programas. Me refiero a la sección connectionStrings, y a la sección appSettings.

 En la sección connectionStrings, se guardan cadenas de conexión a bases de datos, mientras que en appSettings se guardan pares clave-valor que posteriormente podemos recuperar desde la aplicación. Un ejemplo de fichero de configuración puede ser el siguiente:

 <?xml version="1.0" encoding="utf-8" ?>

<configuration>
   <connectionStrings>

    <add name="DB2" connectionString="Provider=IBMDADB2;Data Source=DSNRNP;" />
    <add name="SQL" connectionString="Data Source=CARGASIP;Initial Catalog=Mercury;Persist Security Info=True;User ID=us123;Password=1234" />
  </connectionStrings>
  <appSettings>

    <add key="Licencia" value="123456"/>
    <add key="rutaImagenes" value="c:\imagenes"/>
  </appSettings>

</configuration>

 

Si queremos podemos hacer una encriptación de las secciones:

 

Configuration cm = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

ConfigurationSection cs = cm.GetSection("connectionStrings");

if (!cs.SectionInformation.IsProtected)
   {

     cs.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");

            

cs.SectionInformation.ForceSave = true;

cm.Save(ConfigurationSaveMode.Full);

    }

Por defecto, .Net incluye dos algoritmos de encriptación:DataProtectionConfigurationProvider y RsaProtectedConfigurationProvider. El primero realiza una encriptación usando la librería DPAPI (Data Protection API de Windows). El segundo usa una pareja de claves pública/privada para encriptar por RSA, y es el que se usará si no se indica ningún algoritmo de encriptación. Ambos métodos son bastante seguros, aunque el DPAPI añade la seguridad de que la clave es específica del ordenador en el que se ejecuta la aplicación (con las ventajas e inconvenientes que ello conlleva).

 Para encriptar la sección appSettings, realizaríamos un proceso análogo:

 

ConfigurationSection apps = cm.GetSection("appSettings");

if (!apps.SectionInformation.IsProtected)

 

{

                apps.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");

apps.SectionInformation.ForceSave = true;

cm.Save(ConfigurationSaveMode.Full);

}

Hemos visto que no resultaría complicado encriptar todo el appSettings para que no se pudiera acceder al valor de la licencia. ¿Pero que ocurre con el valor de rutaImagenes?. También se encriptaría, y poder cambiar el valor de esa clave simplemente abriendo el fichero de configuración con un editor de texto sería imposible, lo que nos obligaría a compilar otra vez la aplicación o programar algo que nos permitiera modificar el valor desde el programa. Vemos ahora que sería muy útil poder encriptar solo ciertos valores del appSettings y otros no. Ahora bien, lo que hemos visto hasta ahora, cifraba todo el appSettings. ¿Cómo podríamos resolver este problema?

Una posible solución pasa por crear una sección personalizada, similar al appSettings, y guardar ahí los valores sensibles que queramos encriptar, dejando la sección appSettings sin encriptar, y perfectamente modificable (aunque, por supuesto, se podría hacer al revés).

Por ejemplo, 

<configSections>

    <section name="mySettings" type="System.Configuration.NameValueSectionHandler" />   

  </configSections>

 

<mySettings>

    <add key="Licencia2" value="123456"/>

</mySettings>

 Y ahora encriptamos:

Configuration cm = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

ConfigurationSection ms = cm.GetSection("mySettings");

 

if (!ms.SectionInformation.IsProtected)

 {

                ms.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");

ms.SectionInformation.ForceSave = true;

cm.Save(ConfigurationSaveMode.Full);

 }

 

En mi caso se presenta distintas problemáticas y que pregunto al grupo:

0. ¿Alguna otra solución elegante para encriptar ciertos valores del appsettings?

1. ¿En qué momento sería mejor (best way) hacer la encriptación por código de la sección personalizada ? Si se hace al inicio de la aplicación (sea Windows Forms o ASP.NET) es algo que no me convence.
Se podría hacer en la máquina de desarrollo, antes de desplegar o instalar la aplicación en  una máquina de producción, lo cual puede ser bastante incómodo, además de tener que "acordarse" de la encriptación. Eso se solucionaría con un script automatizado (tipo msbuild) para de alguna forma realizar la encriptación.

2. Si la encriptación usa DPAPI, se realiza basándose en la máquina donde se encripta, por tanto, la encriptación se debería hacer en el momento del despliegue o la instalación,  y no en la primera ejecución (en evento Page_load o Form_Load). Esto enlaza con la idea de scripts automatizados de despliegue(deploy).

Si se utiliza MsBuild o similares para automatizar el deploy, necesitaríamos algún Tasks para poder realizarlo, o incluso un Exec Command a alguna utilidad que nos permita hacerlo (me pregunto si con aspnet_regiis ???).

Si fuese un Installer (imaginamos que teniendo un setup.msi), podría ser algo así como vi en foros de MSDN, pasando la información necesaria al contexto del Installer (Custom Action):


Configuration config =ConfigurationManager.OpenExeConfiguration(<executable path>);

if (config == null) return;

ConfigurationSection section = config.GetSection(<section name>);

if (section == null) return;

// Make sure that the section is not yet protected

if (section.SectionInformation.IsProtected) return;

if (section.SectionInformation.IsLocked) return;

//Protecting the specified section with the specified provider

section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");

// Force saving of the section

section.SectionInformation.ForceSave = true;

config.Save(ConfigurationSaveMode.Modified);


3. Para Windows Forms y ASP.NET , ¿es posible utilizar el comando aspnet_regiis.exe -pef "seccionConfig" para automatizar la encriptación en el proceso deploy o instalación?


Referencias:

http://msdn2.microsoft.com/en-us/library/89211k9b(VS.80).aspx

http://msdn2.microsoft.com/en-us/library/system.configuration.sectioninformation.protectsection.aspx


There are two protected configuration providers included with ASP.NET: RSAProtectedConfigurationProvider and

DPAPIProtectedConfigurationProvider. 

RSAProtectedConfigurationProvider uses the RSACryptoServiceProvider to encrypt configuration sections

using RSA public key encryption to encrypt and decrypt data.

DPAPIProtectedConfigurationProvider uses the Windows Data Protection API (DPAPI) to encrypt configuration sections using the built-in

cryptography capabilities of Windows. You can also create your own protected settings providers if needed. While a user will have a hard time dealing with encrypted data, ASP.NET has no problems. You can use both of these providers in ASP.NET code.

Saludos y gracias.

cibrax

unread,
Sep 14, 2011, 8:36:47 AM9/14/11
to AltNet-Hispano
Para una licencia, encriptacion quizas no sea la mejor solucion. Yo lo
he resuelto en el pasado utilizando un archivo con los datos de la
licencia y firmado con una clave privada. Tu codigo simplementente
tiene que incluir la clave publica para verificar que la licencia no
ha sido alterada. Entre los datos de la licencia, se puede incluir si
tu producto es trial o no, la fecha de expiracion, o cualquier cosa
que tu creas conveniente.

Saludos
Pablo.

On Sep 13, 6:47 pm, Kiquenet <kique...@gmail.com> wrote:
> Por regla general, en un fichero *App.Config*, podemos encontrar dos
> secciones predefinidas, que son las que se usan habitualmente en los
> programas. Me refiero a la sección *connectionStrings*, y a la sección *
> appSettings*.
>
>  En la sección *connectionStrings*, se guardan cadenas de conexión a bases
> de datos, mientras que en *appSettings* se guardan pares clave-valor que
> posteriormente podemos recuperar desde la aplicación. Un ejemplo de fichero
> de configuración puede ser el siguiente:
>
>  <?xml version="1.0" encoding="utf-8" ?>
>
> <configuration>
>    <connectionStrings>
>
>     <add name="DB2" connectionString="Provider=IBMDADB2;Data Source=DSNRNP;"/>
>     <add name="SQL" connectionString="Data Source=CARGASIP;Initial
> Catalog=Mercury;Persist Security Info=True;User ID=us123;Password=1234" />
>   </connectionStrings>
>   <appSettings>
>
>     <add key="Licencia" value="123456"/>
>     <add key="rutaImagenes" value="c:\imagenes"/>
>   </appSettings>
>
> </configuration>
>
> Si queremos podemos hacer una encriptación de las secciones:
>
> Configuration cm = ConfigurationManager.OpenExeConfiguration(
> ConfigurationUserLevel.None);
>
> ConfigurationSection cs = cm.GetSection("connectionStrings");
> if (!cs.SectionInformation.IsProtected)
>    {
>
>      cs.SectionInformation.ProtectSection(
> "DataProtectionConfigurationProvider");
>
> cs.SectionInformation.ForceSave = true;
>
> cm.Save(ConfigurationSaveMode.Full);
>
>     }
>
> Por defecto, .Net incluye dos algoritmos de encriptación:*
> DataProtectionConfigurationProvider* y *RsaProtectedConfigurationProvider*.
> El primero realiza una encriptación usando la librería DPAPI (Data
> Protection API de Windows). El segundo usa una pareja de claves
> pública/privada para encriptar por RSA, y es el que se usará si no se indica
> ningún algoritmo de encriptación. Ambos métodos son bastante seguros, aunque
> el DPAPI añade la seguridad de que la clave es específica del ordenador en
> el que se ejecuta la aplicación (con las ventajas e inconvenientes que ello
> conlleva).
>
>  Para encriptar la sección *appSettings*, realizaríamos un proceso análogo:
>
> ConfigurationSection apps = cm.GetSection("appSettings");
>
> if (!apps.SectionInformation.IsProtected)
>
> {
>
>                 apps.SectionInformation.ProtectSection(
> "DataProtectionConfigurationProvider");
>
> apps.SectionInformation.ForceSave = true;
>
> cm.Save(ConfigurationSaveMode.Full);
>
> }
>
> Hemos visto que no resultaría complicado encriptar todo el *appSettings*para que no se pudiera acceder al valor de la licencia. ¿Pero que ocurre con
> el valor de *rutaImagenes*?. También se encriptaría, y poder cambiar el
> valor de esa clave simplemente abriendo el fichero de configuración con un
> editor de texto sería imposible, lo que nos obligaría a compilar otra vez la
> aplicación o programar algo que nos permitiera modificar el valor desde el
> programa. Vemos ahora que sería muy útil poder encriptar solo ciertos
> valores del *appSettings* y otros no. Ahora bien, lo que hemos visto hasta
> ahora, cifraba todo el *appSettings*. ¿Cómo podríamos resolver este
> problema?
>
> Una posible solución pasa por crear una sección personalizada, similar al *
> appSettings*, y guardar ahí los valores sensibles que queramos encriptar,
> dejando la sección *appSettings* sin encriptar, y perfectamente modificable
> section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvide­r");
> // Force saving of the section
>
> section.SectionInformation.ForceSave = true;
>
> config.Save(ConfigurationSaveMode.Modified);
>
> 3. Para Windows Forms y ASP.NET , ¿es posible utilizar el comando aspnet_regiis.exe
> -pef "seccionConfig" para automatizar la encriptación en el proceso deploy o
> instalación?
>
> Referencias:
>
> http://msdn2.microsoft.com/en-us/library/89211k9b(VS.80).aspx
>
> http://msdn2.microsoft.com/en-us/library/system.configuration.section...

Kiquenet

unread,
Sep 14, 2011, 8:58:53 AM9/14/11
to altnet-...@googlegroups.com
Sería para aplicarlo a un caso general con valores a encriptar como passwords de todo tipo u otra información sensible,


<configSections>
<section name="ImpersonationSettings" type="System.Configuration.NameValueSectionHandler" />
</configSections>


<ImpersonationSettings>

<add key="VSIntegration.ImpersonationWcfServices.User" value="" />
<add key="VSIntegration.ImpersonationWcfServices.Password" value="xxxxxxxxxx" />

<add key="VSIntegration.ImpersonationAccesoRemoto.User" value="xxxxxxxxx" />
<add key="VSIntegration.ImpersonationAccesoRemoto.Password" value="xxxxxxxxxxxx" />
</ImpersonationSettings>

cibrax

unread,
Sep 14, 2011, 9:09:22 AM9/14/11
to AltNet-Hispano
Lo de firmar la licencia, lo podes encontrar tambien en un proyecto de
nuestro amigo Ayende,

http://jagregory.com/writings/rhino-licensing/

Saludos.

Kiquenet

unread,
Sep 15, 2011, 5:01:59 AM9/15/11
to altnet-...@googlegroups.com
Gracias, lo tendré en cuenta para temas de licencia. Tiene buena pinta.

Por ahora, me interesa la encriptación de sección personalizadas usando msbuild o algún comando, a ver si alguien tiene una idea concreto al respecto, seguiré investigando sobre ello.

Alejandro Labra

unread,
Sep 15, 2011, 10:31:02 AM9/15/11
to altnet-...@googlegroups.com
Hola Kiquenet:

Creo que la pregunta es por que deseas encriptar el app.config, ya que yo opino de igual forma que Pablo, creo que si el objetivo es que el "Usuario" no vea, ni modifique ninguna configuración del app.config, lo mejor es crear un archivo y firmarlo con una clave privada.

Ten en cuenta que si encriptas,el usuario igualmente puede modificar la configuración.

Saludos
Alejandro

Reply all
Reply to author
Forward
0 new messages