Compartir a través de


Proteger las cadenas de conexión y otros datos de configuración (C#)

por Scott Mitchell

Descargar PDF

Una aplicación ASP.NET normalmente almacena información de configuración en un archivo Web.config. Parte de esta información es confidencial y garantiza la protección. De forma predeterminada, este archivo no se servirá a un visitante del sitio web, pero un administrador o hacker pueden obtener acceso al sistema de archivos del servidor web y ver el contenido del archivo. En este tutorial, aprendemos que ASP.NET 2.0 nos permite proteger la información confidencial mediante el cifrado de secciones del archivo Web.config.

Introducción

La información de configuración de las aplicaciones de ASP.NET se almacena normalmente en un archivo XML denominado Web.config. A lo largo de estos tutoriales, hemos actualizado el Web.config varias veces. Al crear el conjunto de datos con tipo Northwind en el primer tutorial, por ejemplo, la información de la cadena de conexión se agregó automáticamente a Web.config en la sección <connectionStrings>. Más adelante, en el tutorial Páginas maestras y navegación del sitio, actualizamos Web.config manualmente, agregando un elemento <pages> que indica que todas las páginas de ASP.NET del proyecto deben usar el tema DataWebControls.

Dado que Web.config puede contener datos confidenciales, como cadenas de conexión, es importante que el contenido de Web.config se mantenga protegido y oculto de los espectadores no autorizados. De forma predeterminada, el motor de ASP.NET controla cualquier solicitud HTTP a un archivo con la extensión .config, que devuelve el mensaje Este tipo de página no se sirve que se muestra en la Figura 1. Esto significa que los visitantes no pueden ver el contenido del archivo Web.config simplemente escribiendo http://www.YourServer.com/Web.config en su barra de direcciones del explorador.

Visitar Web.config a través de un explorador devuelve un mensaje de Este tipo de página no se sirve

Figura 1: visitar Web.config a través de un explorador devuelve un mensaje de Este tipo de página no se sirve (haga clic para ver la imagen a tamaño completo)

Pero, ¿qué ocurre si un atacante puede encontrar alguna otra vulnerabilidad que le permita ver el contenido del archivo Web.config? ¿Qué podría hacer un atacante con esta información y qué pasos se pueden realizar para proteger aún más la información confidencial dentro de Web.config? Afortunadamente, la mayoría de las secciones de Web.config no contienen información confidencial. ¿Qué daño puede perpetrar un atacante si conoce el nombre del tema predeterminado usado por las páginas ASP.NET?

Sin embargo, algunas secciones de Web.config contienen información confidencial que puede incluir cadenas de conexión, nombres de usuario, contraseñas, nombres de servidor, claves de cifrado, etc. Esta información se encuentra normalmente en las siguientes secciones Web.config:

  • <appSettings>
  • <connectionStrings>
  • <identity>
  • <sessionState>

En este tutorial veremos técnicas para proteger dicha información de configuración confidencial. Como veremos, la versión 2.0 de .NET Framework incluye un sistema de configuraciones protegidas que hace que las secciones de configuración seleccionadas se cifren y descifren mediante programación.

Nota:

En este tutorial se concluye con un vistazo a las recomendaciones de Microsoft para conectarse a una base de datos desde una aplicación de ASP.NET. Además de cifrar las cadenas de conexión, puede ayudar a proteger el sistema asegurándose de que se conecta a la base de datos de forma segura.

Paso 1: explorar las opciones de configuración protegidas de ASP.NET 2.0

ASP.NET 2.0 incluye un sistema de configuración protegido para cifrar y descifrar información de configuración. Esto incluye métodos de .NET Framework que se pueden usar para cifrar o descifrar la información de configuración mediante programación. El sistema de configuración protegido usa el modelo de proveedor que permite a los desarrolladores elegir qué implementación criptográfica se usa.

.NET Framework se incluye con dos proveedores de configuración protegidos:

Dado que el sistema de configuración protegido implementa el patrón de diseño del proveedor, es posible crear su propio proveedor de configuración protegido y conectarlo a la aplicación. Consulte Implementar un proveedor de configuración protegido para obtener más información sobre este proceso.

Los proveedores RSA y DPAPI usan claves para sus rutinas de cifrado y descifrado, y estas claves se pueden almacenar en el nivel de equipo o usuario. Las claves de nivel de máquina son ideales para escenarios en los que la aplicación web se ejecuta en su propio servidor dedicado o si hay varias aplicaciones en un servidor que necesitan compartir información cifrada. Las claves de nivel de usuario son una opción más segura en entornos de hospedaje compartidos en los que otras aplicaciones del mismo servidor no deben poder descifrar las secciones de configuración protegida de la aplicación.

En este tutorial, nuestros ejemplos usarán el proveedor de DPAPI y las claves de nivel de máquina. En concreto, veremos el cifrado de la sección <connectionStrings> en Web.config, aunque el sistema de configuración protegido se puede usar para cifrar la mayoría de las secciones de Web.config. Para obtener información sobre el uso de claves de nivel de usuario o el uso del proveedor RSA, consulte los recursos de la sección Lecturas adicionales al final de este tutorial.

Nota:

Los proveedores de RSAProtectedConfigurationProvider y DPAPIProtectedConfigurationProvider se registran en el archivo machine.config con los nombres de proveedor RsaProtectedConfigurationProvider y DataProtectionConfigurationProvider, respectivamente. Al cifrar o descifrar la información de configuración, necesitaremos proporcionar el nombre de proveedor adecuado (RsaProtectedConfigurationProvider o DataProtectionConfigurationProvider) en lugar del nombre de tipo real (RSAProtectedConfigurationProvider y DPAPIProtectedConfigurationProvider). Puede encontrar el archivo machine.config en la carpeta $WINDOWS$\Microsoft.NET\Framework\version\CONFIG.

Paso 2: secciones de configuración de cifrado y descifrado mediante programación

Con algunas líneas de código podemos cifrar o descifrar una sección de configuración determinada mediante un proveedor especificado. El código, como veremos en breve, simplemente necesita hacer referencia mediante programación a la sección de configuración adecuada, llamar a su método ProtectSection o UnprotectSection y, a continuación, llamar al método Save para conservar los cambios. Además, .NET Framework incluye una utilidad de línea de comandos útil que puede cifrar y descifrar la información de configuración. Exploraremos esta utilidad de línea de comandos en el paso 3.

Para ilustrar mediante programación la protección de la información de configuración, vamos a crear una página ASP.NET que incluya botones para cifrar y descifrar la sección <connectionStrings> en Web.config.

Para empezar, abra la página EncryptingConfigSections.aspx en la carpeta AdvancedDAL. Arrastre un control de Cuadro de texto desde el Cuadro de herramientas hasta el Diseñador, estableciendo su propiedad ID en WebConfigContents, su propiedad TextMode en MultiLine, y sus propiedades Width y Rows en 95 % y 15, respectivamente. Este control de Cuadro de texto mostrará el contenido de Web.config que nos permite ver rápidamente si el contenido está cifrado o no. Por supuesto, en una aplicación real nunca querrá mostrar el contenido de Web.config.

Debajo del Cuadro de texto, agregue dos controles de botón denominados EncryptConnStrings y DecryptConnStrings. Establezca sus propiedades Texto en Cifrar cadenas de conexión y Descifrar cadenas de conexión.

En este momento, la pantalla debe ser similar a la Figura 2.

Captura de pantalla que muestra Visual Studio abierto en la página de EncryptingConfigSections.aspx, que tiene un nuevo control TextBox y dos botones.

Figura 2: agregar un Cuadro de texto y dos controles web de botón a la página (haga clic para ver la imagen a tamaño completo)

A continuación, es necesario escribir código que cargue y muestre el contenido de Web.config en el Cuadro de texto de WebConfigContents cuando se cargue la página por primera vez. Agregue el código siguiente a la clase de código subyacente de la página. Este código agrega un método denominado DisplayWebConfig y lo llama desde el controlador de eventos Page_Load cuando Page.IsPostBack sea false:

protected void Page_Load(object sender, EventArgs e)
{
    // On the first page visit, call DisplayWebConfig method
    if (!Page.IsPostBack)
        DisplayWebConfig();
}
private void DisplayWebConfig()
{
    // Reads in the contents of Web.config and displays them in the TextBox
    StreamReader webConfigStream = 
        File.OpenText(Path.Combine(Request.PhysicalApplicationPath, "Web.config"));
    string configContents = webConfigStream.ReadToEnd();
    webConfigStream.Close();
    WebConfigContents.Text = configContents;
}

El método DisplayWebConfig usa la clase File para abrir el archivo Web.config de la aplicación, la clase StreamReader para leer su contenido en una cadena y la clase Path para generar la ruta de acceso física al archivo Web.config. Estas tres clases se encuentran en el espacio de nombres System.IO. Por lo tanto, deberá agregar una instrucción using System.IO a la parte superior de la clase de código subyacente o, como alternativa, coloque a estos nombres de clase el prefijo System.IO..

A continuación, es necesario agregar controladores de eventos para los dos eventos de controles de botón Click y agregar el código necesario para cifrar y descifrar la sección <connectionStrings> mediante una clave de nivel de máquina con el proveedor DPAPI. En el Diseñador, haga doble clic en cada uno de los botones para agregar un controlador de eventos Click en la clase de código subyacente y agregue el código siguiente:

protected void EncryptConnStrings_Click(object sender, EventArgs e)
{
    // Get configuration information about Web.config
    Configuration config = 
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    // Let's work with the <connectionStrings> section
    ConfigurationSection connectionStrings = config.GetSection("connectionStrings");
    if (connectionStrings != null)
        // Only encrypt the section if it is not already protected
        if (!connectionStrings.SectionInformation.IsProtected)
        {
            // Encrypt the <connectionStrings> section using the 
            // DataProtectionConfigurationProvider provider
            connectionStrings.SectionInformation.ProtectSection(
                "DataProtectionConfigurationProvider");
            config.Save();
            
            // Refresh the Web.config display
            DisplayWebConfig();
        }
}
protected void DecryptConnStrings_Click(object sender, EventArgs e)
{
    // Get configuration information about Web.config
    Configuration config = 
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    // Let's work with the <connectionStrings> section
    ConfigurationSection connectionStrings = 
        config.GetSection("connectionStrings");
    if (connectionStrings != null)
        // Only decrypt the section if it is protected
        if (connectionStrings.SectionInformation.IsProtected)
        {
            // Decrypt the <connectionStrings> section
            connectionStrings.SectionInformation.UnprotectSection();
            config.Save();
            // Refresh the Web.config display
            DisplayWebConfig();
        }
}

El código usado en los dos controladores de eventos es casi idéntico. Ambos comienzan obteniendo información sobre el archivo Web.config de la aplicación actual a través del método OpenWebConfiguration de la clase WebConfigurationManager. Este método devuelve el archivo de configuración web para la ruta de acceso virtual especificada. A continuación, se accede a la sección <connectionStrings> del archivo Web.config a través del método GetSection(sectionName) de la clase Configuration, que devuelve un objeto ConfigurationSection.

El objeto ConfigurationSection incluye una propiedad SectionInformation que proporciona información adicional y funcionalidad sobre la sección de configuración. Como se muestra en el código anterior, podemos determinar si la sección de configuración está cifrada comprobando la propiedad SectionInformation de la propiedad IsProtected. Además, la sección se puede cifrar o descifrar a través de las propiedades SectionInformation de ProtectSection(provider) y los métodos UnprotectSection.

El método ProtectSection(provider) acepta como entrada una cadena que especifica el nombre del proveedor de configuración protegido que se va a usar al cifrar. En el controlador de eventos de botón EncryptConnString pasamos DataProtectionConfigurationProvider al método ProtectSection(provider) para que se use el proveedor DPAPI. El método UnprotectSection puede determinar el proveedor que se usó para cifrar la sección de configuración y, por lo tanto, no requiere ningún parámetro de entrada.

Después de llamar al método ProtectSection(provider) o UnprotectSection, debe llamar al método Save del objeto Configuration para conservar los cambios. Una vez que la información de configuración se ha cifrado o descifrado y los cambios guardados, llamamos a DisplayWebConfig para cargar el contenido de Web.config actualizado en el control de Cuadro de texto.

Una vez que haya escrito el código anterior, pruébelo visitando la página de EncryptingConfigSections.aspx a través de un explorador. Debería ver inicialmente una página que muestra el contenido de Web.config con la sección <connectionStrings> que se muestra en texto sin formato (vea la Figura 3).

Captura de pantalla que muestra la página EncryptingConfigSections.aspx cargada en un explorador web.

Figura 3: agregar un Cuadro de texto y dos controles web de botón a la página (haga clic para ver la imagen a tamaño completo)

Ahora haga clic en el botón Cifrar cadenas de conexión. Si la validación de solicitudes está habilitada, el marcado publicado de nuevo desde el Cuadro de texto WebConfigContents generará un HttpRequestValidationException, que muestra el mensaje: Se detectó un valor de Request.Form potencialmente peligroso desde el cliente. La validación de solicitudes, que está habilitada de forma predeterminada en ASP.NET 2.0, prohíbe los postbacks que incluyen HTML sin codificar y está diseñada para ayudar a evitar ataques por inyección de scripts. Esta comprobación se puede deshabilitar en el nivel de página o aplicación. Para desactivarla para esta página, establezca el valor de ValidateRequest en false en la directiva @Page. La directiva @Page se encuentra en la parte superior del marcado declarativo de la página.

<%@ Page ValidateRequest="False" ... %>

Para obtener más información sobre la validación de solicitudes, su propósito, cómo deshabilitarla en el nivel de página y aplicación, además de cómo codificar el marcado HTML, vea Validación de solicitudes: prevención de ataques de scripts.

Después de deshabilitar la validación de solicitudes para la página, intente volver a hacer clic en el botón Cifrar cadenas de conexión. En postback, se tendrá acceso al archivo de configuración y se cifrará su sección <connectionStrings> mediante el proveedor DPAPI. El Cuadro de texto se actualiza para mostrar el nuevo contenido Web.config. Como se muestra en la figura 4, la información de <connectionStrings> ahora está cifrada.

Al hacer clic en el botón Cifrar cadenas de conexión, se cifra la sección <connectionString>

Figura 4: al hacer clic en el botón Cifrar cadenas de conexión se cifra la sección <connectionString> (haga clic para ver la imagen a tamaño completo)

La sección <connectionStrings> cifrada generada en mi equipo sigue mostrándose, aunque parte del contenido del elemento <CipherData> se ha quitado por brevedad:

<connectionStrings 
    configProtectionProvider="DataProtectionConfigurationProvider">
  <EncryptedData>
    <CipherData>
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/...zChw==</CipherValue>
    </CipherData>
  </EncryptedData>
</connectionStrings>

Nota:

El elemento <connectionStrings> especifica el proveedor utilizado para realizar el cifrado (DataProtectionConfigurationProvider). El método UnprotectSection usa esta información cuando se hace clic en el botón Descifrar cadenas de conexión.

Cuando se accede a la información de la cadena de conexión desde Web.config, ya sea por código que se escribe, desde un control SqlDataSource o desde el código generado automáticamente desde TableAdapters en nuestros DataSets con tipo, se descifra automáticamente. En resumen, no es necesario agregar ningún código o lógica adicional para descifrar la sección cifrada <connectionString>. Para demostrar esto, visite uno de los tutoriales anteriores en este momento, como el tutorial de visualización simple de la sección Informes básicos (~/BasicReporting/SimpleDisplay.aspx). Como se muestra en la figura 5, el tutorial funciona exactamente como se esperaría, lo que indica que la página de ASP.NET descifra automáticamente la información de la cadena de conexión cifrada.

La capa de acceso a datos descifra automáticamente la información de la cadena de conexión

Figura 5: la capa de acceso a datos descifra automáticamente la información de cadena de conexión (haga clic para ver la imagen a tamaño completo)

Para revertir la sección <connectionStrings> a su representación de texto sin formato, haga clic en el botón Descifrar cadenas de conexión. En postback, debería ver las cadenas de conexión en Web.config en texto sin formato. En este punto, su pantalla debería parecerse a la que tenía la primera vez que visitó esta página (véase la Figura 3).

Paso 3: cifrar secciones de configuración mediante aspnet_regiis.exe

.NET Framework incluye una variedad de herramientas de línea de comandos en la carpeta $WINDOWS$\Microsoft.NET\Framework\version\. En el tutorial Usar dependencias de caché de SQL, por ejemplo, hemos examinado el uso de la herramienta de línea de comandos aspnet_regsql.exe para agregar la infraestructura necesaria para las dependencias de caché de SQL. Otra herramienta de línea de comandos útil de esta carpeta es la Herramienta de Registro de IIS de ASP.NET (aspnet_regiis.exe). Como su nombre implica, la herramienta de Registro de IIS de ASP.NET se usa principalmente para registrar una aplicación de ASP.NET 2.0 con el servidor web de nivel profesional de Microsoft, IIS. Además de sus características relacionadas con IIS, la herramienta de registro de IIS de ASP.NET también se puede usar para cifrar o descifrar secciones de configuración especificadas en Web.config.

En la siguiente instrucción se muestra la sintaxis general que se usa para cifrar una sección de configuración con la herramienta de línea de comandos aspnet_regiis.exe:

aspnet_regiis.exe -pef section physical_directory -prov provider

section es la sección de configuración para cifrar (como connectionStrings ), physical_directory es la ruta de acceso física completa al directorio raíz de la aplicación web y provider es el nombre del proveedor de configuración protegido que se va a usar (como DataProtectionConfigurationProvider ). Como alternativa, si la aplicación web está registrada en IIS, puede escribir la ruta de acceso virtual en lugar de la ruta de acceso física mediante la siguiente sintaxis:

aspnet_regiis.exe -pe section -app virtual_directory -prov provider

En el siguiente ejemplo de aspnet_regiis.exe se cifra la sección <connectionStrings> mediante el proveedor DPAPI con una clave de nivel de máquina:

aspnet_regiis.exe -pef
"connectionStrings" "C:\Websites\ASPNET_Data_Tutorial_73_CS"
-prov "DataProtectionConfigurationProvider"

Del mismo modo, la herramienta de línea de comandos aspnet_regiis.exe se puede usar para descifrar secciones de configuración. En lugar de usar el modificador -pef, use -pdf (o en lugar de -pe, use -pd). Además, tenga en cuenta que el nombre del proveedor no es necesario al descifrar.

aspnet_regiis.exe -pdf section physical_directory
  -- or --
aspnet_regiis.exe -pd section -app virtual_directory

Nota:

Puesto que usamos el proveedor DPAPI, que usa claves específicas del equipo, debe ejecutar aspnet_regiis.exe desde la misma máquina desde la que se sirven las páginas web. Por ejemplo, si ejecuta este programa de línea de comandos desde el equipo de desarrollo local y, a continuación, carga el archivo Web.config cifrado en el servidor de producción, este no podrá descifrar la información de la cadena de conexión, ya que se cifró mediante claves específicas de la máquina de desarrollo. El proveedor RSA no tiene esta limitación, ya que es posible exportar las claves RSA a otra máquina.

Descripción de las opciones de autenticación de base de datos

Antes de que cualquier aplicación pueda emitir consultas SELECT, INSERT, UPDATE o DELETE a una base de datos de Microsoft SQL Server, la base de datos primero debe identificar al solicitante. Este proceso se conoce como autenticación y SQL Server proporciona dos métodos para ello:

  • Autenticación de Windows: el proceso en el que se ejecuta la aplicación se usa para comunicarse con la base de datos. Al ejecutar una aplicación de ASP.NET a través de Visual Studio 2005 s ASP.NET Development Server, la aplicación ASP.NET asume la identidad del usuario que ha iniciado sesión actualmente. Para aplicaciones de ASP.NET en Microsoft Internet Information Server (IIS), las aplicaciones de ASP.NET suelen asumir la identidad de domainName``\MachineName o domainName``\NETWORK SERVICE, aunque esto se puede personalizar.
  • Autenticación de SQL: se proporcionan un identificador de usuario y valores de contraseña como credenciales para la autenticación. Con la autenticación de SQL, el identificador de usuario y la contraseña se proporcionan en la cadena de conexión.

La autenticación de Windows se prefiere sobre la autenticación de SQL porque es más segura. Con la autenticación de Windows, la cadena de conexión está libre de un nombre de usuario y una contraseña y, si el servidor web y el servidor de bases de datos residen en dos máquinas diferentes, las credenciales no se envían a través de la red en texto sin formato. Por su parte, con la autenticación de SQL, las credenciales de autenticación se codifican de forma rígida en la cadena de conexión y se transmiten desde el servidor web al servidor de base de datos en texto sin formato.

Estos tutoriales han usado la autenticación de Windows. Puede indicar qué modo de autenticación se usa inspeccionando la cadena de conexión. La cadena de conexión de Web.config para nuestros tutoriales ha sido:

Data Source=.\SQLEXPRESS; AttachDbFilename=|DataDirectory|\NORTHWND.MDF; Integrated Security=True; User Instance=True

La Integrated Security=True y la falta de un nombre de usuario y una contraseña indican que se está usando la autenticación de Windows. En algunas cadenas de conexión, el término Trusted Connection=Yes o Integrated Security=SSPI se usa en lugar de Integrated Security=True, pero los tres indican el uso de la autenticación de Windows.

En el ejemplo siguiente se muestra una cadena de conexión que usa la autenticación de SQL. $CREDENTIAL_PLACEHOLDER$ es un marcador de posición para el par clave-valor de contraseña. Tenga en cuenta que las credenciales se insertan dentro de la cadena de conexión:

Server=serverName; Database=Northwind; uid=userID; $CREDENTIAL_PLACEHOLDER$

Imagine que un atacante puede ver el archivo Web.config s de la aplicación. Si usa la autenticación de SQL para conectarse a una base de datos accesible a través de Internet, el atacante puede usar esta cadena de conexión para conectarse a la base de datos a través de SQL Management Studio o desde páginas ASP.NET en su propio sitio web. Para ayudar a mitigar esta amenaza, cifre la información de la cadena de conexión en Web.config mediante el sistema de configuración protegido.

Nota:

Para obtener más información sobre los distintos tipos de autenticación disponibles en SQL Server, vea Crear aplicaciones ASP.NET seguras: autenticación, autorización y comunicación seguras. Para obtener más ejemplos de cadenas de conexión que ilustran las diferencias entre la sintaxis de autenticación de Windows y SQL, consulte ConnectionStrings.com.

Resumen

De forma predeterminada, no se puede acceder a los archivos con una extensión .config en una aplicación de ASP.NET a través de un explorador. Estos tipos de archivos no se devuelven porque pueden contener información confidencial, como cadenas de conexión de base de datos, nombres de usuario y contraseñas, etc. El sistema de configuración protegido de .NET 2.0 ayuda a proteger aún más la información confidencial al permitir que se cifren las secciones de configuración especificadas. Hay dos proveedores de configuración protegidos integrados: uno que usa el algoritmo RSA y otro que usa la API de protección de datos de Windows (DPAPI).

En este tutorial hemos visto cómo cifrar y descifrar las opciones de configuración mediante el proveedor DPAPI. Esto se puede lograr mediante programación, como vimos en el paso 2, así como a través de la herramienta de línea de comandos aspnet_regiis.exe, que se ha tratado en el paso 3. Para obtener más información sobre el uso de claves de nivel de usuario o el uso del proveedor RSA en su lugar, consulte los recursos de la sección Lectura adicional.

¡Feliz programación!

Lecturas adicionales

Para obtener más información sobre los temas tratados en este tutorial, consulte los siguientes recursos:

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha trabajado con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Puede ponerse en contacto con él a través de mitchell@4GuysFromRolla.com. o de su blog, que se puede encontrar en http://ScottOnWriting.NET.

Agradecimientos especiales a

Esta serie de tutoriales fue revisada por muchos revisores de gran ayuda. Los revisores principales de este tutorial fueron Teresa Murphy y Randy Schmidt. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, escríbame a mitchell@4GuysFromRolla.com.