保护连接字符串和其他配置信息 (VB)

作者 :Scott Mitchell

下载 PDF

ASP.NET 应用程序通常将配置信息存储在 Web.config 文件中。 其中一些信息是敏感信息,需要保护。 默认情况下,此文件不会提供给网站访问者,但管理员或黑客可能会访问 Web 服务器的文件系统并查看文件的内容。 在本教程中,我们了解 ASP.NET 2.0 允许我们通过加密 Web.config 文件的部分来保护敏感信息。

简介

ASP.NET 应用程序的配置信息通常存储在名为 的 Web.configXML 文件中。 在这些教程的过程中,我们更新了 Web.config 几次。 例如,Northwind在第一个教程中创建类型化数据集时,连接字符串信息会自动添加到 Web.config<connectionStrings> 部分中。 稍后,在 母版页和网站导航 教程中,我们手动更新 Web.config了 ,添加了一个 <pages> 元素,指示项目中的所有 ASP.NET 页面都应使用 DataWebControls 主题。

由于 Web.config 可能包含敏感数据(如连接字符串),因此必须保护 的内容 Web.config ,并隐藏未经授权的查看者。 默认情况下,对扩展名为 .config 的文件的任何 HTTP 请求都由 ASP.NET 引擎处理,该引擎返回图 1 中所示 的“未提供此类型的页面” 消息。 这意味着访问者无法通过直接输入http://www.YourServer.com/Web.config浏览器的地址栏来查看文件Web.config的内容。

通过浏览器访问 Web.config 返回“未提供此类型的页面”消息

图 1:通过浏览器访问 Web.config 返回未提供这种类型的页面 消息 (单击以查看全尺寸图像)

但是,如果攻击者能够找到允许她查看文件 Web.config 内容的其他攻击,该怎么办? 攻击者可以对此信息执行哪些操作?可以采取哪些步骤进一步保护中的 Web.config敏感信息? 幸运的是,中的 Web.config 大多数部分不包含敏感信息。 如果攻击者知道你的 ASP.NET 页面使用的默认主题的名称,会造成什么伤害?

但是,某些 Web.config 部分包含可能包括连接字符串、用户名、密码、服务器名称、加密密钥等的敏感信息。 此信息通常位于以下 Web.config 部分:

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

在本教程中,我们将介绍用于保护此类敏感配置信息的技术。 我们将看到,.NET Framework版本 2.0 包含一个受保护的配置系统,使以编程方式加密和解密所选配置部分变得轻而易举。

注意

本教程最后介绍 Microsoft 关于从 ASP.NET 应用程序连接到数据库的建议。 除了加密连接字符串外,还可以通过确保以安全的方式连接到数据库来帮助强化系统。

步骤 1:探索 ASP.NET 2.0 s 受保护的配置选项

ASP.NET 2.0 包括用于加密和解密配置信息的受保护配置系统。 这包括.NET Framework中可用于以编程方式加密或解密配置信息的方法。 受保护的配置系统使用提供程序模型,使开发人员能够选择所使用的加密实现。

.NET Framework附带两个受保护的配置提供程序:

由于受保护的配置系统实现了提供程序设计模式,因此可以创建自己的受保护配置提供程序并将其插入到应用程序中。 有关此过程的详细信息 ,请参阅实现受保护的配置提供程序

RSA 和 DPAPI 提供程序使用密钥进行加密和解密例程,这些密钥可以存储在计算机或用户级别。 计算机级密钥非常适合 Web 应用程序在其自己的专用服务器上运行,或者服务器上有多个应用程序需要共享加密信息的情况。 在共享托管环境中,用户级密钥是更安全的选项,同一服务器上的其他应用程序不应能够解密应用程序的受保护配置节。

在本教程中,我们的示例将使用 DPAPI 提供程序和计算机级密钥。 具体而言,我们将介绍如何加密 <connectionStrings> 中的 Web.config节,尽管受保护的配置系统可用于加密大多数任何 Web.config 部分。 有关使用用户级密钥或使用 RSA 提供程序的信息,请参阅本教程末尾的“进一步阅读”部分中的资源。

注意

RSAProtectedConfigurationProviderDPAPIProtectedConfigurationProvider 提供程序分别使用提供程序名称和 DataProtectionConfigurationProviderRsaProtectedConfigurationProvider 在 文件中注册machine.config。 加密或解密配置信息时,我们需要提供相应的提供程序名称 (RsaProtectedConfigurationProviderDataProtectionConfigurationProvider) ,而不是 (RSAProtectedConfigurationProviderDPAPIProtectedConfigurationProvider) 的实际类型名称。 可以在 文件夹中找到 machine.config 该文件 $WINDOWS$\Microsoft.NET\Framework\version\CONFIG

步骤 2:以编程方式加密和解密配置部分

通过几行代码,我们可以使用指定的提供程序加密或解密特定的配置节。 稍后将看到,代码只需以编程方式引用相应的配置部分,调用其 ProtectSectionUnprotectSection 方法,然后调用 Save 方法来保留更改。 此外,.NET Framework包括一个有用的命令行实用工具,可以加密和解密配置信息。 我们将在步骤 3 中探索此命令行实用工具。

为了说明如何以编程方式保护配置信息,让我们创建一个 ASP.NET 页,其中包含用于加密和解密 中的 节的<connectionStrings>Web.config按钮。

首先打开 EncryptingConfigSections.aspx 文件夹中的页面 AdvancedDAL 。 将 TextBox 控件从“工具箱”拖到Designer上,分别将其 ID 属性WebConfigContents设置为 ,将 TextMode 属性设置为 MultiLine,将 和 WidthRows 属性分别设置为 95% 和 15。 此 TextBox 控件将显示 的内容 Web.config ,使我们能够快速查看内容是否已加密。 当然,在实际应用程序中,你永远不希望显示 的内容 Web.config

在 TextBox 下,添加两个名为 和 DecryptConnStringsEncryptConnStrings按钮控件。 将其 Text 属性设置为“加密连接字符串”和“解密连接字符串”。

此时,屏幕应类似于图 2。

显示 Visual Studio 已打开到EncryptingConfigSections.aspx页的屏幕截图,该页具有一个新的 TextBox 和两个按钮控件。

图 2:将 TextBox 和两个按钮 Web 控件添加到页面 (单击以查看全尺寸图像)

接下来,我们需要编写代码,用于在首次加载页面时在 TextBox 中WebConfigContents加载和显示 的内容Web.config。 将以下代码添加到页面代码隐藏类。 此代码添加名为 DisplayWebConfig 的方法,并在 为 FalsePage.IsPostBackPage_Load事件处理程序调用它:

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    'On the first page visit, call DisplayWebConfig method
    If Not Page.IsPostBack Then
        DisplayWebConfig()
    End If
End Sub
Private Sub DisplayWebConfig()
    'Reads in the contents of Web.config and displays them in the TextBox
    Dim webConfigStream As StreamReader = _
        File.OpenText(Path.Combine(Request.PhysicalApplicationPath, "Web.config"))
    Dim configContents As String = webConfigStream.ReadToEnd()
    webConfigStream.Close()
    WebConfigContents.Text = configContents
End Sub

方法DisplayWebConfig使用 File打开应用程序 文件Web.config使用StreamReader将其内容读入字符串,并使用 Path生成文件的物理路径Web.config。 这三个类都在 命名空间中找到System.IO。 因此,需要将 语句添加到 Imports``System.IO 代码隐藏类的顶部,或者,将这些类名添加为 System.IO.

接下来,我们需要为两个 Button 控件 Click 事件添加事件处理程序,并添加必要的代码,以便使用计算机级密钥和 DPAPI 提供程序对节进行加密和解密 <connectionStrings> 。 在Designer,双击每个 Buttons 以在代码隐藏类中添加Click事件处理程序,然后添加以下代码:

Protected Sub EncryptConnStrings_Click(sender As Object, e As EventArgs) _
    Handles EncryptConnStrings.Click
    'Get configuration information about Web.config
    Dim config As Configuration = _
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath)
    ' Let's work with the <connectionStrings> section
    Dim connectionStrings As ConfigurationSection = _
        config.GetSection("connectionStrings")
    If connectionStrings IsNot Nothing Then
        ' Only encrypt the section if it is not already protected
        If Not connectionStrings.SectionInformation.IsProtected Then
            ' Encrypt the <connectionStrings> section using the 
            ' DataProtectionConfigurationProvider provider
            connectionStrings.SectionInformation.ProtectSection( _
                "DataProtectionConfigurationProvider")
            config.Save()
            ' Refresh the Web.config display
            DisplayWebConfig()
        End If
    End If
End Sub
Protected Sub DecryptConnStrings_Click(sender As Object, e As EventArgs) _
    Handles DecryptConnStrings.Click
    ' Get configuration information about Web.config
    Dim config As Configuration = _
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath)
    ' Let's work with the <connectionStrings> section
    Dim connectionStrings As ConfigurationSection = _
        config.GetSection("connectionStrings")
    If connectionStrings IsNot Nothing Then
        ' Only decrypt the section if it is protected
        If connectionStrings.SectionInformation.IsProtected Then
            ' Decrypt the <connectionStrings> section
            connectionStrings.SectionInformation.UnprotectSection()
            config.Save()
            ' Refresh the Web.config display
            DisplayWebConfig()
        End If
    End If
End Sub

这两个事件处理程序中使用的代码几乎完全相同。 它们首先通过 WebConfigurationManager s Web.configOpenWebConfiguration 方法获取有关当前应用程序 文件的信息。 此方法返回指定虚拟路径的 Web 配置文件。 接下来,Web.config通过 Configuration方法GetSection(sectionName)访问文件 s <connectionStrings> 部分,该方法返回 对象ConfigurationSection

对象 ConfigurationSection 包含一个 SectionInformation 属性 ,该属性提供有关配置节的其他信息和功能。 如上面的代码所示,我们可以通过检查 SectionInformation 属性 属性 IsProtected 来确定配置节是否已加密。 此外,可以通过 属性 ProtectSection(provider)UnprotectSection 方法对 节进行加密或解密SectionInformation

方法 ProtectSection(provider) 接受一个字符串作为输入,该字符串指定加密时要使用的受保护配置提供程序的名称。 在 EncryptConnString Button 事件处理程序中,我们将 DataProtectionConfigurationProvider 传递到 ProtectSection(provider) 方法,以便使用 DPAPI 提供程序。 方法 UnprotectSection 可以确定用于加密配置节的提供程序,因此不需要任何输入参数。

调用 ProtectSection(provider)UnprotectSection 方法后,必须调用 Configuration 对象 方法Save以保留更改。 加密或解密配置信息并保存更改后,我们将调用 DisplayWebConfig 以将更新 Web.config 的内容加载到 TextBox 控件中。

输入上述代码后,通过浏览器访问页面对其进行 EncryptingConfigSections.aspx 测试。 最初应看到一个页面,其中列出了 的内容 Web.config<connectionStrings> 部分以纯文本显示 (请参阅图 3) 。

显示 Web 浏览器中加载EncryptingConfigSections.aspx页面的屏幕截图。

图 3:将 TextBox 和两个按钮 Web 控件添加到页面 (单击以查看全尺寸图像)

现在,单击“加密连接字符串”按钮。 如果启用了请求验证,则从 WebConfigContents TextBox 回发的标记将生成 , HttpRequestValidationException该标记显示消息“从客户端检测到潜在危险 Request.Form 值”。 ASP.NET 2.0 中默认启用的请求验证禁止包含未编码 HTML 的回发,旨在帮助防止脚本注入攻击。 可以在页面或应用程序级别禁用此检查。 若要关闭此页面的此设置,请在 ValidateRequest 指令中@Page将 设置设置为 False 。 指令 @Page 位于页面 声明性标记的顶部。

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

有关请求验证、其用途、如何在页面和应用程序级别禁用它以及如何对标记进行 HTML 编码的详细信息,请参阅 请求验证 - 防止脚本攻击

禁用页面的请求验证后,再次尝试单击“加密连接字符串”按钮。 回发时,将访问配置文件并使用 DPAPI 提供程序加密其 <connectionStrings> 部分。 然后,将更新 TextBox 以显示新 Web.config 内容。 如图 4 所示, <connectionStrings> 信息现已加密。

单击“加密连接字符串”按钮将 <加密 connectionString> 部分

图 4:单击“加密连接字符串”按钮加密部分 <connectionString> (单击以查看全尺寸图像)

尽管 为简洁起见,元素中的<CipherData>某些内容已被删除,但随后将在计算机上生成的加密<connectionStrings>部分:

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

注意

元素 <connectionStrings> 指定用于执行加密 () DataProtectionConfigurationProvider 的提供程序。 单击“解密连接字符串”按钮时, UnprotectSection 方法将使用此信息。

当从 Web.config 中访问连接字符串信息时(无论是通过我们编写的代码、从 SqlDataSource 控件访问,还是从类型化数据集中的 TableAdapters 自动生成的代码),它会自动解密。 简言之,我们不需要添加任何额外的代码或逻辑来解密加密 <connectionString> 的节。 若要演示这一点,请访问之前的教程之一,例如基本报告部分 (~/BasicReporting/SimpleDisplay.aspx) 的简单显示教程。 如图 5 所示,本教程的工作方式与预期完全一致,指示 ASP.NET 页自动解密加密连接字符串信息。

数据访问层自动解密连接字符串信息

图 5:数据访问层自动解密连接字符串信息 (单击以查看全尺寸图像)

若要将分区还原<connectionStrings>回其纯文本表示形式,请单击“解密连接字符串”按钮。 回发时,应看到纯文本格式的 Web.config 连接字符串。 此时,屏幕应与第一次访问此页面时的外观一样, (如图 3) 所示。

步骤 3:使用 aspnet_regiis.exe 加密配置节

.NET Framework文件夹中包含各种命令行工具$WINDOWS$\Microsoft.NET\Framework\version\。 例如,在 “使用 SQL 缓存依赖项” 教程中,我们介绍了如何使用 aspnet_regsql.exe 命令行工具添加 SQL 缓存依赖项所需的基础结构。 此文件夹中另一个有用的命令行工具是 () aspnet_regiis.exe ASP.NET IIS 注册工具 。 顾名思义,ASP.NET IIS 注册工具主要用于向 Microsoft 专业级 Web 服务器 IIS 注册 ASP.NET 2.0 应用程序。 除了 IIS 相关功能外,ASP.NET IIS 注册工具还可用于加密或解密 中的 Web.config指定配置部分。

以下语句显示了用于使用命令行工具加密配置节的 aspnet_regiis.exe 常规语法:

aspnet_regiis.exe -pef section physical_directory -prov provider

section 是用于加密 connectionStrings ) 等 (的配置部分, physical_directory 是 Web 应用程序根目录的完整物理路径, 提供程序 是使用 dataProtectionConfigurationProvider ) 等 (受保护配置提供程序的名称。 或者,如果在 IIS 中注册了 Web 应用程序,则可以使用以下语法输入虚拟路径而不是物理路径:

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

以下示例 aspnet_regiis.exe 使用 DPAPI 提供程序和计算机级密钥加密 <connectionStrings> 节:

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

同样, aspnet_regiis.exe 命令行工具可用于解密配置部分。 使用 -pef (,而不是 使用 开关, -pdf 而不是 -pe使用 -pd) 。 另请注意,解密时不需要提供程序名称。

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

注意

由于我们使用的是 DPAPI 提供程序,该提供程序使用特定于计算机的密钥,因此您必须从提供网页的同一台计算机运行 aspnet_regiis.exe 。 例如,如果从本地开发计算机运行此命令行程序,然后将加密 Web.config 文件上传到生产服务器,则生产服务器将无法解密连接字符串信息,因为该信息是使用特定于开发计算机的密钥加密的。 RSA 提供程序没有此限制,因为可以将 RSA 密钥导出到另一台计算机。

了解数据库身份验证选项

在任何应用程序可以向 Microsoft SQL Server 数据库发出 SELECTINSERTUPDATE、 或 DELETE 查询之前,数据库首先必须标识请求者。 此过程称为身份验证,SQL Server提供两种身份验证方法:

  • Windows 身份验证 - 运行应用程序的过程用于与数据库通信。 通过 Visual Studio 2005 ASP.NET Development Server 运行 ASP.NET 应用程序时,ASP.NET 应用程序假定当前登录用户的标识。 对于 Microsoft Internet Information Server (IIS) 上的 ASP.NET 应用程序,ASP.NET 应用程序通常采用 或 domainName``\NETWORK SERVICEdomainName``\MachineName标识,尽管这可以自定义。
  • SQL 身份验证 - 用户 ID 和密码值作为身份验证凭据提供。 使用 SQL 身份验证时,用户 ID 和密码在连接字符串中提供。

Windows 身份验证优先于 SQL 身份验证,因为它更安全。 使用 Windows 身份验证 连接字符串不使用用户名和密码,如果 Web 服务器和数据库服务器驻留在两个不同的计算机上,则不会通过网络以纯文本形式发送凭据。 但是,使用 SQL 身份验证时,身份验证凭据在连接字符串中硬编码,并且以纯文本形式从 Web 服务器传输到数据库服务器。

这些教程使用了 Windows 身份验证。 可以通过检查连接字符串来判断正在使用的身份验证模式。 教程连接字符串Web.config为:

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

集成安全性=True 且缺少用户名和密码表示正在使用Windows 身份验证。 在某些连接字符串中,使用术语“受信任的连接=是”或“集成安全性=SSPI”而不是“集成安全性=True”,但这三者都表示使用Windows 身份验证。

以下示例演示使用 SQL 身份验证的连接字符串。 请注意嵌入在连接字符串中的凭据:

Server=serverName; Database=Northwind; uid=userID; pwd=password

假设攻击者能够查看应用程序的 Web.config 文件。 如果使用 SQL 身份验证连接到可通过 Internet 访问的数据库,攻击者可以使用此连接字符串通过 SQL Management Studio 或自己网站上的 ASP.NET 页连接到数据库。 若要帮助缓解此威胁,请使用受保护的配置系统加密连接字符串信息Web.config

注意

有关 SQL Server 中提供的不同类型的身份验证的详细信息,请参阅构建安全 ASP.NET 应用程序:身份验证、授权和安全通信。 有关说明 Windows 和 SQL 身份验证语法差异的进一步连接字符串示例,请参阅 ConnectionStrings.com

总结

默认情况下,无法通过浏览器访问 ASP.NET 应用程序中扩展名 .config 为的文件。 不会返回这些类型的文件,因为它们可能包含敏感信息,例如数据库连接字符串、用户名和密码等。 .NET 2.0 中的受保护配置系统通过允许加密指定的配置部分来帮助进一步保护敏感信息。 有两个内置受保护的配置提供程序:一个使用 RSA 算法,一个使用 Windows 数据保护 API (DPAPI) 。

本教程介绍了如何使用 DPAPI 提供程序加密和解密配置设置。 这可以通过编程方式实现(如步骤 2 中所示),也可以通过 aspnet_regiis.exe 步骤 3 中介绍的命令行工具来实现。 有关改用用户级密钥或使用 RSA 提供程序的详细信息,请参阅进一步阅读部分中的资源。

编程快乐!

深入阅读

有关本教程中讨论的主题的详细信息,请参阅以下资源:

关于作者

斯科特·米切尔是七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自 1998 年以来一直在使用 Microsoft Web 技术。 Scott 担任独立顾问、培训师和作家。 他的最新一本书是 山姆斯在 24 小时内 ASP.NET 2.0。 可以在 上mitchell@4GuysFromRolla.com联系他,也可以通过他的博客(可在 中找到http://ScottOnWriting.NET)。

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是特蕾莎·墨菲和兰迪·施密特。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处mitchell@4GuysFromRolla.com放置一行。