在ASP.NET 2.0中操作数据之七十一:保护连接字符串及其它设置信息_自学过程

导言:

  ASP.NET应用程序的设置信息通常都存储在一个名为Web.config的XML文件里。在教程的前面部分我们已经好几次修改过Web.config文件了.比如在第一章,我们创建名为Northwind的数据集时,数据库连接字符串信息自动的添加到Web.config文件的<connectionStrings>节点.再后来,在第3章里,我们手动更新了Web.config文件,添加了一个<pages>元素,对所有的ASP.NET页面运用DataWebControls主题.

  由于Web.config文件包含了敏感的信息,比如连接字符串.所以确保Web.config文件内容的安全性是很重要的,对未经授权的访问者应隐藏这些敏感信息.默认情况下,对.config后缀名的文件的任何HTTP请求都由ASP.NET引擎来处理,它将返回“This type of page is not served”的信息,如图1所示.这意味着访问者无法通过在其浏览器的地址栏键入‘http://www.YourServer.com/Web.config'来访问你的Web.config文件.


图1:通过浏览器访问Web.config将返回“This type of page is not served”的信息

  但是如果某个攻击者找到其它方法来访问你的Web.config文件的内容又怎么办呢?他会做怎样的修改?我们又采取怎样的步骤来保护Web.config文件的这些信息呢?幸运的是,Web.config文件的绝大多数节点并不包含敏感信息.如果攻击者知道你的ASP.NET页面使用的默认的主题的名字又会搞哪些破坏呢?

  Web.config文件的某些节点包含了敏感信息,比如:connection strings, user names, passwords, server names, encryption keys等等.我们能在下面的这些节点找到这些信息:

.<appSettings>
.<connectionStrings>
.<identity>
.<sessionState>

  在本文我们将考察保护这些敏感信息的技术.就像我们将看到的那样,.NET Framework 2.0版本包含了一个保护配置系统,我们可以使用它很容易地对选定的配置节点进行加密和解密.

  注意:在本文结尾部分,我们将看到微软对从一个ASP.NET应用程序连接到数据库时的建议.除了对连接字符串进行加密外,我们还可以连接到一个处于“安全模式”的数据库使你的系统更强大.

第一步:考察ASP.NET 2.0的保护配置选项

ASP.NET 2.0包含一个保护配置系统以对配置信息进行加密和解密.这些方法包含在.NET Framework,可用来编程加密和解密配置信息.该保护配置系统使用provider model模式.它允许开发者选择执行哪种加密.

.NET Framework包含了2种protected configuration providers:

.RSAProtectedConfigurationProvider :加密和解密时使用不对称RSA运算法则(RSA algorithm)

.DPAPIProtectedConfigurationProvider:加密和解密时使用Windows Data Protection API (DPAPI)

由于保护配置系统执行的是provider design模式,因此我们可以创建自己的protected configuration provider并运用到自己的程序里.具体过程可参阅文章《Implementing a Protected Configuration Provider》(http://msdn2.microsoft.com/en-us/library/wfc2t3az(VS.80).aspx)

  RSA providers 和 DPAPI providers在加密和解密时使用“密匙”(keys),这些“密匙”可以存储在“机器级”(Machine-level)和“用户级”(user-level).机器级密匙在这种情况下很理想:每个web应用程序都运行在自己专有的服务器上,或某个服务器上的多个应用程序共享同样的加密信息.而用户级密匙在共享服务器环境里是比较理想的安全选择.此时,同服务器上的其它程序不能对你加密的配置信息进行解密.

  本教程的示例将使用DPAPI provider和机器级密匙.具体来说,我们将对Web.config文件里的<connectionStrings>节点进行加密.对RSA provider以及用户级密匙的更多信息请参考本文结束部分的外延阅读资料.

  注意:RSAProtectedConfigurationProvider 和DPAPIProtectedConfigurationProvider providers在machine.config文件里被分别组册成RsaProtectedConfigurationProvider 和DataProtectionConfigurationProvider。当我们对配置信息进行加密或解密时我们需要提供相应的provider名称(即RsaProtectedConfigurationProvider 或 DataProtectionConfigurationProvider);而不是实际的类型名(即RSAProtectedConfigurationProvider 和 DPAPIProtectedConfigurationProvider). 你可以在$WINDOWS$/Microsoft.NET/Framework/version/CONFIG文件夹里找到machine.config文件.

第二步:通过编程加密和解密配置节点

  使用某个provider,我们只需要很少的几行代码就可以对某个配置节点加密或解密.这些代码仅仅需要引用相应的配置节点,调用其ProtectSection 或 UnprotectSection方法,再调用Save方法来执行.另外,.NET Framework包含了一个很有用的命令行功能来进行加密和解密,我们将在第3步考察该功能.

  为了便于演示,我们需要创建一个包含按钮的ASP.NET页面,以便于对Web.config文件的<connectionStrings>节点进行加密和解密.

  打开AdvancedDAL文件夹里的EncryptingConfigSections.aspx页面,拖一个TextBox控件到页面,设其ID为WebConfigContents;TextMode属性为MultiLine;Width和Rows属性分别为95% 和 15.该TextBox控件用于显示Web.config文件的内容,以查看其内容是否已经加密了.当然,在现实程序里,我们不可能将Web.config文件的内容显示出来.

  在该TextBox控件下面添加2个Button控件,ID分别为EncryptConnStrings 和 DecryptConnStrings;设其Text属性为“Encrypt Connection Strings” 和 “Decrypt Connection Strings”.

此时你的界面看起来和下面的差不多:


图2:在页面上添加一个TextBox控件和2个Button控件

  接下来,在页面初次登录时我们需要在ID为WebConfigContents的TextBox控件里将Web.config文件的内容显示出来。在页面的后台类里添加如下的代码,该代码添加了一个名为DisplayWebConfig的方法,在Page_Load事件处理器里,当Page.IsPostBack 为 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;
}

  该DisplayWebConfig方法调用File class类来打开应用程序的Web.config文件;调用StreamReader class类将内容读入一个字符串;再调用Path class类来获取Web.config文件的物理地址.这3个类都位于System.IO命名空间.所以我们应该在后台类的顶部添加using System.IO声明,又或者在这些类的前面添加“System.IO.”前缀.

  接下来,我们需要为这2个按钮的Click事件添加事件处理器,在一个DPAPI provider里使用机器级密匙对<connectionStrings>节点进行加密和解密.在设计器里,双击这2个按钮以添加Click事件处理器,添加如下代码:

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();
 }
}

  这2个按钮的事件处理器的代码几乎是一样的.它们一开始都通过WebConfigurationManager class类的OpenWebConfiguration方法获取当前应用程序的Web.config文件的信息. 该方法根据指定的有效路径返回web配置文件。接下来,再通过Configuration class类的GetSection(sectionName)方法访问Web.config文件的<connectionStrings>节点.该方法返回一个ConfigurationSection对象.

  该ConfigurationSection对象包含了一个SectionInformation属性,用来阐述加密节点的其它相关信息. 就像上面的代码显示的那样,我们通过查看SectionInformation的IsProtected属性来判断是否对配置节点进行了加密.此外,还可以通过SectionInformation的ProtectSection(provider) 和 UnprotectSection方法对节点进行加密或解密.

  ProtectSection(provider)方法有一个字符串类型的输入参数,该参数指定了用来加密的protected configuration provider的名称。在EncryptConnString按钮的事件处理器里,我们将“DataProtectionConfigurationProvider”传递给ProtectSection(provider)方法,因此指明了用到的是DPAPI provider.而UnprotectSection方法可以确定加密时用到的provider,因此不需要任何的输入参数.

  调用ProtectSection(provider) 或 UnprotectSection方法后,我还必须调用Configuration对象的Save method方法来进行具体的操作. 一旦完成加密或解密并保存后,我们调用DisplayWebConfig方法将更新后的Web.config文件的内容上传到TextBox控件.

  键入上述代码后,在浏览器里测试EncryptingConfigSections.aspx页面,最开始你将看到页面将Web.config文件的<connectionStrings>节点的内容以纯文本的形式展示出来.


图3:显示<connectionStrings>节点的内容

  现在,点击“Encrypt Connection Strings”按钮,如果“请求确认”(request validation)处于激活状态的话,回传页面时将抛出一个HttpRequestValidationException异常,显示一个消息:“A potentially dangerous Request.Form value was detected from the client.”。这个Request validation,在ASP.NET 2.0里默认为处于激活状态,禁止服务器接受含有未编码的HTML的内容,它被设计来保护服务器免受注入式脚本的攻击.可以从页面或应用程序来禁止该功能.我们在该页禁用它,在页面声明代码的顶部的的@Page标记里ValidateRequest设置为false,如下:

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

  在禁用该功能后,再次点击“Encrypt Connection Strings”按钮,页面回传后就可以访问配置文件了,并用DPAPI provider对<connectionStrings>节点进行加密. TextBox控件然后将Web.config文件更新后的内容显示出来,如图4所示,<connectionStrings>节点的信息现在已经被加密了.


图4:点击“Encrypt Connection Strings”按钮对<connectionString>节点进行加密

在加密前,我暂时地将<CipherData>元素里的内容转移了:

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

  注意:<connectionStrings>元素指定了用来加密的provider(即DataProtectionConfigurationProvider).当点击“Decrypt Connection Strings”按钮时UnprotectSection方法将会用到该信息.对于加密的连接字符串,系统可以自动的对其解密.简而言之,我们不需要再对加密的<connectionString>节点添加任何其它的代码。我们来做个验证,打开以前的教程,比如(~/BasicReporting/SimpleDisplay.aspx页面),如图5所示,页面像我们期望的那样工作正常,这就表明了经过加密的连接字符串被ASP.NET页面自动解密了.


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

  为将加密的<connectionStrings>节点恢复到纯文本样式,点击“Decrypt Connection Strings”按钮。页面回传后,你将看到Web.config文件里的连接字符串恢复到纯文本样式.此时,屏幕开起来像是最初登录的样子(见图3)

第三步:用aspnet_regiis.exe对配置节点进行加密

  .NET Framework包含了很多的命令行工具,可以在$WINDOWS$/Microsoft.NET/Framework/version/ folder文件夹里找到这些工具.以第59章《使用SQL缓存依赖项SqlCacheDependency 》为例,我们用aspnet_regsql.exe命令行工具为SQL缓存依赖添加里必要的体系结构.该文件夹里的另一个有用的工具是ASP.NET IIS Registration tool (aspnet_regiis.exe). 就像其名字暗示的那样,这个ASP.NET IIS Registration工具主要用来在微软专业Web server,IIS上注册ASP.NET 2.0应用程序.

  除了其与IIS相关的属性外,该ASP.NET IIS Registration工具也可以对Web.config文件的配置节点进行加密和解密. 下面的是使用aspnet_regiis.exe命令行工具对配置节点加密的常规代码:

aspnet_regiis.exe -pef section physical_directory -prov provider

  其中section是要加密的配置节点(比如“connectionStrings”);physical_directory 为web应用程序根节点的完整物理路径;provider是用到的protected configuration provider的名称(比如“DataProtectionConfigurationProvider”). 另外,如果你将web应用程序在IIS里进行了注册了的话,你就可以用相当路径来代替绝对路径:

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

  下面为使用aspnet_regiis.exe的例子,它用DPAPI provider,机器级密匙,对<connectionStrings>节点进行加密:

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

  类似的,该aspnet_regiis.exe命令行工具也可以用来解密配置节点,不过我们要将-pef替换成-pdf或-pd。当然,解密时不需要指定provider名称.

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

  注意:由于我们使用的是DPAPI provider,它使用的密匙是又电脑指定的,所以你必须在存储web页面的同一台电脑上运行aspnet_regiis.exe工具. 比如,你在本地电脑上运行这个命令行,然后又将加了密的连接字符串上载到另一个服务器上,该服务器就无法对其进行解密,因为加密的密匙是在本地电脑上指定的.如果是使用RSA provider的话就不存在这种局限性,因为RSA provider可以将密匙(RSA keys)传递给另一台电脑.

理解Database Authentication Options

  在任何应用程序向Microsoft SQL Server数据库发出SELECT,INSERT,UPDATE,或DELETE请求之前,数据库首先要确定请求者的身份.该过程可分为2种验证模式:authentication 和 SQL Server provides:

.Windows Authentication:在Visual Studio 2005的ASP.NET Development Server里运行一个ASP.NET应用程序时,ASP.NET应用程序假定身份(identity)为当前登录用户。而如果运行在Microsoft Internet Information Server (IIS)上的话,ASP.NET应用程序假定身份(identity)为domainName/MachineName or domainName/NETWORK SERVICE,,虽然这些都可以用户定制.

.SQL Authentication:验证的时候需要提供用户ID和password,使用SQL authentication的话,可以由连接字符串来提供ID和password.

  一般使用Windows authentication模式,因为其更安全.在Windows authentication模式下,连接字符串不需要用户名和密码,并且如果web服务器和数据库服务器分属不同的电脑的话,(credentials)认证在网络间传输时并不以纯文本格式传输.而如果是SQL authentication模式的话,将对连接字符串进行硬编码,且认证在web服务器和数据库服务器之间以纯文本格式进行传输.

  本教程使用的是Windows authentication.我们可以通过连接字符串来查看到底使用的是哪种认证。本教程的Web.config文件的连接字符串如下:

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

  术语“Integrated Security=True”,以及缺少用户名和密码都表明我们使用的是Windows authentication模式。不过在一些连接字符串里用术语“Trusted Connection=Yes” 或 “Integrated Security=SSPI”来替换“Integrated Security=True”, 不过它们都表明使用的是Windows authentication.

下面的代码显示使用的是SQL authentication:

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

  假想某个攻击者可以查看你的应用程序的Web.config文件。如果你使用的是SQL authentication模式通过Internet连接到数据库,攻击者可以利用连接字符串通过SQL Management Studio或他自己网站上的ASP.NET页面连接到你的数据库.为降低风险,我们需要对Web.config文件的连接字符串进行加密.

  注意:关于SQL Server里不同认证模式的更多信息应参阅文章《Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication》(http://msdn2.microsoft.com/en-us/library/aa302392.aspx);关于Windows 和 SQL authentication不同之处的更多示例,应参阅ConnectionStrings.com网站.

结语:

  默认情况下,ASP.NET应用程序里的所有以.config为后缀的文件都不能通过浏览器访问.这是因为这些文件可能包含了一些敏感信息,比如:数据库连接字符串、用户名和密码等。 .NET 2.0包含的保护配置系统可以通过对指定的配置节点进行加密来加以保护.有2种内置的protected configuration providers:一个使用RSA运算法则,而另一个使用Windows Data Protection API (DPAPI).

  本文考察了使用DPAPI provider来对配置信息进行加密和解密.我们可以通过编程的方式,就像在第2步探讨的那样;也可以通过使用aspnet_regiis.exe命令行工具,就像在第3步探讨的那样。关于使用RSA provider及用户级密匙的更多信息请参考本文的外延阅读.

  祝编程快乐!

作者简介

  本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用 微软Web技术。大家可以点击查看全部教程《[翻译]Scott Mitchell 的ASP.NET 2.0数据教程》,希望对大家的学习ASP.NET有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索数据库
, asp.net
, 加密
, rsa
, DPAPI
aspnet_regiis
,以便于您获取更多的相关知识。

时间: 2024-11-01 07:07:54

在ASP.NET 2.0中操作数据之七十一:保护连接字符串及其它设置信息_自学过程的相关文章

在ASP.NET 2.0中操作数据之三十:格式化DataList和Repeater的数据_自学过程

导言 在前面的教程里我们学习了DataList提供了一些风格样式的属性.而且我们还学习了如何定义HeadStyle, ItemStyle, AlternatingItemStyle, 和SelectedItemStyle等属性的默认CSS.除了这四个属性外,DataList还提供了其它属性,比如Font, ForeColor, BackColor, 和BorderWidth.而Repeater没有提供任何这样的属性.如果你需要用Reperter来实现这些效果,你就需要在templates里直接写

在ASP.NET 2.0中操作数据之三十二:数据控件的嵌套_自学过程

导言 除了静态HTML和数据绑定语法,template也可以包含Web控件和用户控件.这些控件的属性可以通过声明语法,数据绑定语法或在服务器端通过事件处理编程来设置. 通过将控件嵌入到template里,可以自定义界面,提升用户体验.例如,在在GridView控件中使用TemplateField 里,我们学习了如何通过在GridView的TemplateField里加一个Calendar控件来表示员工的雇佣日期.在给编辑和新增界面增加验证控件 和定制数据修改界面 里,我们学习了如何通过添加验证控

在ASP.NET 2.0中操作数据之五十二:使用FileUpload上传文件_自学过程

导言: 到目前为止,我们的教程围绕的是text数据.然而,很多应用程序既需要处理text数据,也需要处理二进制数据.比如招聘网站可能需要用户上传Word或PDF格式的简历. 使用二进制数据面临一项挑战:在应用程序中如何存储二进制数据.我们必须更新添加记录的界面以支持用户上传本地电脑中的文件,并添加额外的功能以下载某条记录的相关二进制数据.本章以及接下来的3章,我们探讨如何处理这些问题.在本系列教程结束时,我们将创建一个功能完善的应用程序,它为每种类型的记录提供相关的图片和PDF小册子. 在本系列

在ASP.NET 2.0中操作数据之二十六:排序自定义分页数据_自学过程

导言 和默认翻页方式相比,自定义分页能提高几个数量级的效率.当我们的需要对大量数据分页的时候就需要考虑自定义分页,然而实现自定义分页相比默认分页需要做更多工作.对于排序自定义分页数据也是这样,在本教程中我们就会扩展前面的例子来实现自定义分页数据的排序. 注意:既然本教程是基于前一个的,因此我们需要把前面教程示例页面EfficientPaging.aspx的<asp:Content>元素中的代码复制到本教程SortParameter.aspx示例页面中.关于如何进行这样的复制操作请参看为删除数据

在ASP.NET 2.0中操作数据之四十九:为GridView控件添加RadioButton_自学过程

导言: GridView控件提供了大量的内置功能.它包含了一系列的域(field)来显示诸如text.images.hyperlinks和buttons.另外它支持模板(template)用于用户自定义界面.我们可以构建这样一个GridView控件,用户仅需要点击控件里的一个按钮,每一条记录行都可以选择.编辑.删除.除了控件本身内置的功能外,在某些情况下,我们添加一些额外的.控件没有内置的功能.在本章及接下来的2篇教程里我们将探讨如何优化GridView,以支持额外的功能. 本篇及接下来的教程将

在ASP.NET 2.0中操作数据之五十九:使用SQL缓存依赖项SqlCacheDependency_自学过程

导言: 在56和57章探讨的缓存技术使用的是基于时间的缓存周期,当过了某段时间后便将缓存数据从内存清除.当设置缓存时间为x秒时,数据在x秒内都是"新"的.当然,就像在60章谈到的那样,对静态数据来说,x可延伸到web应用程序的整个生命周期(lifetime). 当缓存数据时,基于时间周期的技术因为其易用性而常常被采用,不过又常常不那么完美.理想的状态是这样的:数据库数据还是应缓存在内存,直到源数据(underlying data)发生改变时才从内存清除.这样的话可以最大化的获取缓存带来

在ASP.NET 2.0中操作数据之七十:配置数据库连接和命令等级设置_自学过程

导言: 在本系列我们用类型化的DataSets来构建数据访问层.就像在第一章探讨的那样,类型化DataSets的DataTables用作存储数据的"仓库",而TableAdapters作为连接数据库的通道,以检索.修改数据.TableAdapters 将处理数据库的很多复杂的细节进行了封装,将我们解脱出来,免去了写代码连接数据库.发出命名.向DataTable填充数据的痛苦. 不过在某些时候我们需要深入的探究TableAdapter,直接写代码处理ADO.NET对象.在第61章<

在ASP.NET 2.0中操作数据之七十二:调试存储过程_自学过程

导言: Visual Studio有很多的调试功能.我们只需要稍稍点点鼠标,敲敲键盘就可以使用断点(breakpoints)来打断某个程序的执行,并查看其状态.除了调试代码以外,Visual Studio也支持对SQL Server里面的存储过程进行调试.就像可以在ASP.NET页面的后台代码类或Business Logic Layer class类里设置断点一样,我们也可以在存储过程里设置断点. 本文我们将考察如何在Visual Studio的Server Explorer里进入存储过程并设置

在ASP.NET 2.0中操作数据之七十四:用Managed Code创建存储过程和用户自定义函数(下部分)_自学过程

第八步:从表现层调用Managed Stored Procedures 当对数据访问层和业务逻辑层进行扩充以支持调用GetDiscontinuedProducts 和 GetProductsWithPriceLessThan这2种managed stored procedures后,我们可以在一个ASP.NET页面里展示这些存储过程的结果了. 打开AdvancedDAL文件夹里的ManagedFunctionsAndSprocs.aspx页面,从工具箱拖一个GridView控件到设计器,设其ID