Proteger las cadenas de conexión y otros datos de configuración (C#)
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 un hacker pueden obtener acceso al sistema de archivos del servidor web y ver el contenido del archivo. En este tutorial, veremos 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 ASP.NET aplicaciones se almacena normalmente en un archivo XML denominado Web.config
. A lo largo de estos tutoriales, hemos actualizado un Web.config
puñado de veces. Al crear el Northwind
conjunto de datos con tipo en el primer tutorial, por ejemplo, la información de la cadena de conexión se agregó automáticamente a Web.config
en la <connectionStrings>
sección . Más adelante, en el tutorial Páginas maestras y navegación del sitio , actualizamos Web.config
manualmente , agregando un <pages>
elemento que indica que todas las páginas de ASP.NET de nuestro proyecto deben usar el DataWebControls
tema.
Dado Web.config
que puede contener datos confidenciales, como cadenas de conexión, es importante que el contenido de Web.config
se mantenga seguro y oculto de los visores no autorizados. De forma predeterminada, el motor de ASP.NET controla cualquier solicitud HTTP a un archivo con la .config
extensión , que devuelve el mensaje Este tipo de página no se muestra en la figura 1. Esto significa que los visitantes no pueden ver el Web.config
contenido del archivo simplemente escribiendo http://www.YourServer.com/Web.config en su barra de direcciones del explorador.
Figura 1: Visitar Web.config
a través de un explorador Devuelve un mensaje este tipo de página no se sirve (haga clic para ver la imagen de tamaño completo)
Pero, ¿qué ocurre si un atacante puede encontrar alguna otra vulnerabilidad que le permita ver el Web.config
contenido del archivo? ¿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 Web.config
de ? Afortunadamente, la mayoría de las secciones Web.config
de no contienen información confidencial. ¿Qué daño puede perpetrar un atacante si conoce el nombre del tema predeterminado usado por las páginas de ASP.NET?
Sin embargo, algunas Web.config
secciones 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 secciones siguientes 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
Este tutorial 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 protegida de ASP.NET 2.0
ASP.NET 2.0 incluye un sistema de configuración protegido para cifrar y descifrar la información de configuración. Esto incluye métodos de .NET Framework que se pueden usar para cifrar o descifrar mediante programación información de configuració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:
RSAProtectedConfigurationProvider
: usa el algoritmo RSA asimétrico para el cifrado y el descifrado.DPAPIProtectedConfigurationProvider
: usa la API de protección de datos de Windows (DPAPI) para el cifrado y el descifrado.
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 Implementación de 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 dpAPI y las claves de nivel de máquina. En concreto, veremos cómo cifrar la <connectionStrings>
sección de Web.config
, aunque el sistema de configuración protegido se puede usar para cifrar la mayoría de las Web.config
secciones. 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 RSAProtectedConfigurationProvider
proveedores y DPAPIProtectedConfigurationProvider
se registran en el machine.config
archivo con los nombres RsaProtectedConfigurationProvider
de proveedor y DataProtectionConfigurationProvider
, respectivamente. Al cifrar o descifrar la información de configuración, tendremos que proporcionar el nombre de proveedor adecuado (RsaProtectedConfigurationProvider
o DataProtectionConfigurationProvider
) en lugar del nombre de tipo real (RSAProtectedConfigurationProvider
y DPAPIProtectedConfigurationProvider
). Puede encontrar el machine.config
archivo en la $WINDOWS$\Microsoft.NET\Framework\version\CONFIG
carpeta .
Paso 2: Cifrado y descifrado de secciones de configuración 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 ProtectSection
método o UnprotectSection
y, a continuación, llamar al Save
método 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 la protección mediante programación de la información de configuración, vamos a crear una página de ASP.NET que incluya botones para cifrar y descifrar la <connectionStrings>
sección de Web.config
.
Para empezar, abra la EncryptingConfigSections.aspx
página en la AdvancedDAL
carpeta . Arrastre un control TextBox desde el Cuadro de herramientas al Diseñador, estableciendo su ID
propiedad en , su TextMode
propiedad WebConfigContents
en MultiLine
y sus Width
propiedades y Rows
hasta el 95 % y el 15, respectivamente. Este control TextBox 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 de TextBox, agregue dos controles Button denominados EncryptConnStrings
y DecryptConnStrings
. Establezca sus propiedades text en Encrypt Connection Strings (Cifrar cadenas de conexión) y Decrypt Connection Strings (Descifrar cadenas de conexión).
En este momento, la pantalla debe ser similar a la figura 2.
Figura 2: Agregar un cuadro de texto y dos controles web de botón a la página (haga clic para ver la imagen de tamaño completo)
A continuación, es necesario escribir código que cargue y muestre el contenido de Web.config
en textBox WebConfigContents
cuando se carga por primera vez la página. 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 Page_Load
controlador de eventos cuando Page.IsPostBack
es 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 DisplayWebConfig
método usa la File
clase para abrir el archivo de Web.config
la aplicación, la StreamReader
clase para leer su contenido en una cadena y la Path
clase para generar la ruta de acceso física al Web.config
archivo. Estas tres clases se encuentran en el System.IO
espacio de nombres . Por lo tanto, deberá agregar una using
System.IO
instrucción a la parte superior de la clase de código subyacente o, como alternativa, anteponer estos nombres de clase con System.IO.
.
A continuación, es necesario agregar controladores de eventos para los dos eventos de controles Click
Button y agregar el código necesario para cifrar y descifrar la <connectionStrings>
sección mediante una clave de nivel de equipo con el proveedor DPAPI. En el Diseñador, haga doble clic en cada uno de los botones para agregar un Click
controlador de eventos en la clase de código subyacente y, a continuación, 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 de la Web.config
aplicación actual a través del método s OpenWebConfiguration
de laWebConfigurationManager
clase . Este método devuelve el archivo de configuración web para la ruta de acceso virtual especificada. A continuación, se obtiene acceso a la Web.config
sección del archivo s <connectionStrings>
a través del método de laConfiguration
clase sGetSection(sectionName)
, que devuelve un ConfigurationSection
objeto .
El ConfigurationSection
objeto incluye una SectionInformation
propiedad 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 de la SectionInformation
IsProtected
propiedad . Además, la sección se puede cifrar o descifrar a través de la SectionInformation
propiedad s ProtectSection(provider)
y UnprotectSection
los métodos.
El ProtectSection(provider)
método acepta como entrada una cadena que especifica el nombre del proveedor de configuración protegido que se usará al cifrar. En el EncryptConnString
controlador de eventos Button, pasamos DataProtectionConfigurationProvider al ProtectSection(provider)
método para que se use el proveedor DPAPI. El UnprotectSection
método 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 ProtectSection(provider)
método o UnprotectSection
, debe llamar al método s del Save
Configuration
objeto para conservar los cambios. Una vez que la información de configuración se ha cifrado o descifrado y los cambios guardados, llamamos DisplayWebConfig
a para cargar el contenido actualizado Web.config
en el control TextBox.
Una vez que haya escrito el código anterior, pruebelo visitando la EncryptingConfigSections.aspx
página a través de un explorador. Inicialmente debería ver una página que muestra el contenido de Web.config
con la <connectionStrings>
sección mostrada en texto sin formato (vea la figura 3).
Figura 3: Agregar un cuadro de texto y dos controles web de botón a la página (haga clic para ver la imagen de 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 que se devuelve desde TextBox WebConfigContents
generará un HttpRequestValidationException
, que muestra el mensaje, se detectó un valor potencialmente peligroso Request.Form
del 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ñado 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 la ValidateRequest
configuración false
en en la @Page
directiva . La @Page
directiva 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 finalidad, cómo deshabilitarla en el nivel de página y aplicación, así como sobre cómo codificar HTML el marcado, consulte Validación de solicitudes : prevención de ataques de script.
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 accederá al archivo de configuración y se cifrará su <connectionStrings>
sección mediante el proveedor DPAPI. A continuación, textBox se actualiza para mostrar el nuevo Web.config
contenido. Como se muestra en la figura 4, la <connectionStrings>
información ahora está cifrada.
Figura 4: Hacer clic en el botón Cifrar cadenas de conexión Cifra la <connectionString>
sección (haga clic para ver la imagen de tamaño completo)
La sección cifrada <connectionStrings>
generada en mi equipo sigue, aunque parte del contenido del <CipherData>
elemento se ha quitado por motivos de brevedad:
<connectionStrings
configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData>
<CipherValue>AQAAANCMnd8BFdERjHoAwE/...zChw==</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
Nota
El <connectionStrings>
elemento especifica el proveedor utilizado para realizar el cifrado (DataProtectionConfigurationProvider
). El método usa UnprotectSection
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 código ni lógica adicionales para descifrar la sección cifrada <connectionString>
. Para demostrarlo, 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 ASP.NET descifra automáticamente la información de la cadena de conexión cifrada.
Figura 5: La capa de acceso a datos descifra automáticamente la información de la cadena de conexión (haga clic para ver la imagen de tamaño completo)
Para revertir la <connectionStrings>
sección 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
texto sin formato. En este momento, la pantalla debería tener el aspecto que hizo al visitar esta página por primera vez (vea la figura 3).
Paso 3: Cifrado de secciones de configuración mediante aspnet_regiis.exe
.NET Framework incluye una variedad de herramientas de línea de comandos en la $WINDOWS$\Microsoft.NET\Framework\version\
carpeta . En el tutorial Uso de dependencias de caché de SQL , por ejemplo, hemos examinado el uso de la aspnet_regsql.exe
herramienta de línea de comandos 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 (aspnet_regiis.exe
) de ASP.NET. 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
.
La siguiente instrucción muestra la sintaxis general usada para cifrar una sección de configuración con la herramienta de aspnet_regiis.exe
línea de comandos:
aspnet_regiis.exe -pef section physical_directory -prov provider
section es la sección de configuración para cifrar (como connectionStrings ), el physical_directory es la ruta de acceso física completa al directorio raíz de la aplicación web y el proveedor 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 sintaxis siguiente:
aspnet_regiis.exe -pe section -app virtual_directory -prov provider
En el ejemplo siguiente aspnet_regiis.exe
se cifra la <connectionStrings>
sección mediante el proveedor DPAPI con una clave de nivel de equipo:
aspnet_regiis.exe -pef
"connectionStrings" "C:\Websites\ASPNET_Data_Tutorial_73_CS"
-prov "DataProtectionConfigurationProvider"
De forma similar, la aspnet_regiis.exe
herramienta de línea de comandos se puede usar para descifrar secciones de configuración. En lugar de usar el -pef
modificador, use -pdf
(o en lugar de -pe
, use -pd
). Además, tenga en cuenta que el nombre del proveedor no es necesario al descifrarlo.
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 ejecutarse 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 cifrado Web.config en el servidor de producción, el servidor de producción no podrá descifrar la información de la cadena de conexión, ya que se cifró con 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
Para que cualquier aplicación pueda emitir SELECT
consultas , 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 de autenticación:
- 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 ASP.NET aplicaciones en Microsoft Internet Information Server (IIS), ASP.NET aplicaciones suelen asumir la identidad de
domainName``\MachineName
odomainName``\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.
autenticación de Windows se prefiere sobre la autenticación de SQL porque es más segura. Con 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 base de datos residen en dos máquinas diferentes, las credenciales no se envían a través de la red en texto sin formato. Sin embargo, 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 autenticación de Windows. Puede saber 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 seguridad integrada=True y la falta de un nombre de usuario y una contraseña indican que se está usando autenticación de Windows. En algunas cadenas de conexión, el término Trusted Connection=Sí o Integrated Security=SSPI se usa en lugar de Integrated Security=True, pero los tres indican el uso de 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 de la Web.config
aplicación. Si usa la autenticación de SQL para conectarse a una base de datos a la que se puede acceder 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 ASP.NET páginas en su propio sitio web. Para ayudar a mitigar esta amenaza, cifre la información de la cadena de conexión en Web.config
el uso del sistema de configuración protegido.
Nota
Para obtener más información sobre los diferentes tipos de autenticación disponibles en SQL Server, consulte Building Secure ASP.NET Applications: Authentication, Authorization y Secure Communication. 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 .config
extensión 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, que se ha tratado en el aspnet_regiis.exe
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:
- Creación de una aplicación de ASP.NET segura: autenticación, autorización y comunicación segura
- Cifrado de información de configuración en aplicaciones de ASP.NET 2.0
- Cifrado de
Web.config
valores en ASP.NET 2.0 - Cómo: Cifrar secciones de configuración en ASP.NET 2.0 mediante DPAPI
- Cómo cifrar secciones de configuración en ASP.NET 2.0 utilizando RSA
- La API de configuración en .NET 2.0
- Protección de datos de Windows
Acerca del autor
Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando 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 en 24 Horas. Puede llegar a .mitchell@4GuysFromRolla.com o a través de su blog, que se puede encontrar en http://ScottOnWriting.NET.
Gracias especial a
Muchos revisores útiles revisaron esta serie de tutoriales. Los revisores principales de este tutorial fueron Teresa Murphy y Randy Schmidt. ¿Te interesa revisar mis próximos artículos de MSDN? Si es así, colóqueme una línea en mitchell@4GuysFromRolla.com.