作者 :斯科特·米切尔
ASP.NET 应用程序通常将配置信息存储在 Web.config 文件中。 其中一些信息很敏感,需要保护。 默认情况下,此文件不会提供给网站访问者,但管理员或黑客可能会访问 Web 服务器的文件系统并查看文件的内容。 在本教程中,我们了解到,ASP.NET 2.0 允许通过加密 Web.config 文件的节来保护敏感信息。
介绍
ASP.NET 应用程序的配置信息通常存储在名为 Web.config
的 XML 文件中。 在这些教程的过程中,我们更新 Web.config
了几次。 在第一个教程Northwind
类型化数据集时,连接字符串信息会自动添加到Web.config
该<connectionStrings>
部分中。 稍后,在 母版页和网站导航 教程中,我们手动更新 Web.config
,并添加一个 <pages>
元素,指示项目中的所有 ASP.NET 页都应使用 DataWebControls
主题。
由于Web.config
可能包含敏感数据(如连接字符串),Web.config
因此请务必将内容安全且隐藏在未经授权的查看者中。 默认情况下,对扩展名为 .config
文件的任何 HTTP 请求都由 ASP.NET 引擎处理,该引擎返回 此类型的页面未送达 图 1 中显示的消息。 这意味着访问者只需输入Web.config
浏览器的地址栏即可查看文件http://www.YourServer.com/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 包括一个受保护的配置系统,使以编程方式加密和解密所选配置部分是微风。
注释
本教程总结了关于从 ASP.NET 应用程序连接到数据库的 Microsoft 建议。 除了加密连接字符串之外,还可以通过确保以安全方式连接到数据库来帮助强化系统。
步骤 1:探索 ASP.NET 2.0 s 受保护的配置选项
ASP.NET 2.0 包括用于加密和解密配置信息的受保护配置系统。 这包括 .NET Framework 中可用于以编程方式加密或解密配置信息的方法。 受保护的配置系统使用提供程序模型,使开发人员可以选择使用哪种加密实现。
.NET Framework 附带两个受保护的配置提供程序:
-
RSAProtectedConfigurationProvider
- 使用非对称 RSA 算法 进行加密和解密。 -
DPAPIProtectedConfigurationProvider
- 使用 Windows 数据保护 API (DPAPI) 进行加密和解密。
由于受保护的配置系统实现了提供程序设计模式,因此可以创建自己的受保护的配置提供程序并将其插入应用程序。 有关此过程的详细信息,请参阅 “实现受保护的配置提供程序 ”。
RSA 和 DPAPI 提供程序使用密钥进行加密和解密例程,这些密钥可以存储在计算机或用户级别。 计算机级密钥非常适合 Web 应用程序在其自己的专用服务器上运行的情况,或者如果服务器上有多个应用程序需要共享加密信息。 用户级密钥是共享托管环境中的更安全选项,在同一服务器上其他应用程序不应解密应用程序的受保护配置部分。
在本教程中,我们的示例将使用 DPAPI 提供程序和计算机级密钥。 具体而言,我们将介绍加密 <connectionStrings>
部分 Web.config
,尽管受保护的配置系统可用于加密大多数部分 Web.config
。 有关使用用户级密钥或使用 RSA 提供程序的信息,请参阅本教程末尾的“进一步阅读”部分中的资源。
注释
提供程序RSAProtectedConfigurationProvider
和DPAPIProtectedConfigurationProvider
提供程序分别在machine.config
文件中注册了提供程序名称和RsaProtectedConfigurationProvider
DataProtectionConfigurationProvider
提供程序。 加密或解密配置信息时,我们需要提供适当的提供程序名称(RsaProtectedConfigurationProvider
或 DataProtectionConfigurationProvider
),而不是实际的类型名称(RSAProtectedConfigurationProvider
和 DPAPIProtectedConfigurationProvider
)。 可以在文件夹中找到 machine.config
该文件 $WINDOWS$\Microsoft.NET\Framework\version\CONFIG
。
步骤 2:以编程方式加密和解密配置部分
通过几行代码,可以使用指定的提供程序加密或解密特定配置节。 正如我们很快就会看到的代码,只需以编程方式引用相应的配置部分,调用其 ProtectSection
或 UnprotectSection
方法,然后调用 Save
该方法来保留更改。 此外,.NET Framework 还包含一个有用的命令行实用工具,可用于加密和解密配置信息。 我们将在步骤 3 中探索此命令行实用工具。
为了以编程方式说明如何保护配置信息,让我们创建一个 ASP.NET 页,其中包含用于加密和解密部分中<connectionStrings>
的Web.config
按钮。
首先打开 EncryptingConfigSections.aspx
文件夹中的页面 AdvancedDAL
。 将 TextBox 控件从工具箱拖到设计器上,将其ID
属性WebConfigContents
设置为TextMode
,将MultiLine
属性Width
分别设置为 95% 和 Rows
15。 此 TextBox 控件将显示 Web.config
允许我们快速查看内容是否已加密的内容。 当然,在实际应用程序中,你永远不想显示其内容 Web.config
。
在 TextBox 下面,添加两个名为 EncryptConnStrings
和 DecryptConnStrings
. 将其文本属性设置为“加密连接字符串”和“解密连接字符串”。
此时,屏幕应类似于图 2。
图 2:向页面添加一个 TextBox 和两个按钮 Web 控件(单击以查看全尺寸图像)
接下来,我们需要编写在首次加载页面时加载和显示 TextBox 中Web.config
内容WebConfigContents
的代码。 将以下代码添加到页面代码隐藏类。 此代码添加一个命名DisplayWebConfig
的方法,并在以下Page_Load
情况下Page.IsPostBack
从False
事件处理程序调用该方法:
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
这三个类都位于命名空间System.IO
。 因此,您需要在代码隐藏类的顶部添加Imports``System.IO
语句,或者将这些类名称加上前缀System.IO.
。
接下来,我们需要为两个 Button 控件 Click
事件添加事件处理程序,并添加必要的代码,以便通过 DPAPI 提供程序使用计算机级密钥加密和解密 <connectionStrings>
节。 在设计器中,双击每个 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
两个事件处理程序中使用的代码几乎完全相同。 它们首先通过Web.config
方法WebConfigurationManager
OpenWebConfiguration
获取有关当前应用程序文件的信息。 此方法返回指定虚拟路径的 Web 配置文件。 接下来,Web.config
通过<connectionStrings>
Configuration
方法访问文件GetSection(sectionName)
部分。ConfigurationSection
该 ConfigurationSection
对象包含一个 SectionInformation
属性,该属性 提供有关配置部分的其他信息和功能。 如上面的代码所示,我们可以通过检查 SectionInformation
属性的属性 IsProtected
来确定配置节是否已加密。 此外,可以通过属性和SectionInformation
ProtectSection(provider)
方法对节进行加密或解密UnprotectSection
。
该方法 ProtectSection(provider)
接受为输入字符串,指定加密时要使用的受保护配置提供程序的名称。 在 Button 事件处理程序中 EncryptConnString
,我们将 DataProtectionConfigurationProvider 传递到方法, ProtectSection(provider)
以便使用 DPAPI 提供程序。 该方法 UnprotectSection
可以确定用于加密配置节的提供程序,因此不需要任何输入参数。
调用 ProtectSection(provider)
或 UnprotectSection
方法后,必须调用 Configuration
对象 Save
方法 来保留更改。 加密或解密配置信息并保存更改后,我们调用 DisplayWebConfig
将更新 Web.config
的内容加载到 TextBox 控件中。
输入上述代码后,通过浏览器访问 EncryptingConfigSections.aspx
页面对其进行测试。 最初应看到一个页面,其中列出了以纯文本形式显示的节的内容Web.config
<connectionStrings>
(请参阅图 3)。
图 3:向页面添加一个 TextBox 和两个按钮 Web 控件(单击以查看全尺寸图像)
现在,单击“加密连接字符串”按钮。 如果启用了请求验证,则从 WebConfigContents
TextBox 回发的标记将生成一个显示消息的消息,从客户端检测到一个 HttpRequestValidationException
潜在的危险 Request.Form
值。 请求验证在 ASP.NET 2.0 中默认启用,禁止包含未编码 HTML 的回发,旨在帮助防止脚本注入攻击。 可以在页面或应用程序级别禁用此检查。 若要关闭此页面,请将 ValidateRequest
设置设置为 False
指令中 @Page
。 该 @Page
指令位于页面声明性标记的顶部。
<%@ Page ValidateRequest="False" ... %>
若要详细了解请求验证及其用途、如何在页面和应用程序级别禁用它,以及如何对 HTML 编码标记进行禁用,请参阅 请求验证 - 防止脚本攻击。
禁用页面请求验证后,请尝试再次单击“加密连接字符串”按钮。 在回发时,将访问配置文件及其部分,并使用 <connectionStrings>
DPAPI 提供程序进行加密。 然后更新 TextBox 以显示新 Web.config
内容。 如图 4 所示, <connectionStrings>
信息现已加密。
图 4:单击“加密连接字符串”按钮加密 <connectionString>
分区(单击以查看全尺寸图像)
在我的计算机上生成的加密 <connectionStrings>
部分遵循,尽管元素中的 <CipherData>
某些内容已被删除,但为简洁起见:
<connectionStrings
configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData>
<CipherValue>==</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
注释
该 <connectionStrings>
元素指定用于执行加密的提供程序(DataProtectionConfigurationProvider
)。 单击“解密连接字符串”按钮时,此方法将使用 UnprotectSection
此信息。
从我们编写的代码、SqlDataSource 控件或 Typed DataSets 中的 TableAdapters 自动生成的代码访问连接字符串信息Web.config
时,它会自动解密。 简言之,我们不需要添加任何额外的代码或逻辑来解密加密 <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 缓存依赖项所需的基础结构。 此文件夹中的另一个有用的命令行工具是 ASP.NET IIS 注册工具 (aspnet_regiis.exe
) 。 顾名思义,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
节是加密的配置部分(如 connectionStrings),physical_directory是 Web 应用程序根目录的完整物理路径,提供程序是要使用的受保护配置提供程序的名称(如 DataProtectionConfigurationProvider)。 或者,如果 Web 应用程序在 IIS 中注册,则可以使用以下语法输入虚拟路径,而不是物理路径:
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 数据库发出SELECT
、INSERT
UPDATE
或DELETE
查询之前,数据库必须先标识请求者。 此过程称为 身份验证 ,SQL Server 提供两种身份验证方法:
-
Windows 身份验证 - 运行应用程序的进程用于与数据库通信。 通过 Visual Studio 2005 s ASP.NET Development Server 运行 ASP.NET 应用程序时,ASP.NET 应用程序假定当前登录用户的标识。 对于Microsoft Internet Information Server(IIS)上的 ASP.NET 应用程序,ASP.NET 应用程序通常假定其标识
domainName``\MachineName
domainName``\NETWORK SERVICE
,也可以自定义。 - 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.NET 应用程序:身份验证、授权和安全通信
-
加密
Web.config
ASP.NET 2.0 中的值 - 如何:使用 DPAPI 加密 ASP.NET 2.0 中的配置节
- 如何:使用 RSA 加密 ASP.NET 2.0 中的配置节(可能为英文网页)
- .NET 2.0 中的配置 API
- Windows 数据保护
关于作者
斯科特·米切尔,七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是 《Sams Teach Yourself ASP.NET 2.0 in 24 Hours》。 可以通过 mitchell@4GuysFromRolla.com 联系到他。
特别致谢
本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Teresa Murphy 和 Randy Schmidt。 有兴趣查看即将发布的 MSDN 文章? 如果是这样,请给我写信。mitchell@4GuysFromRolla.com