保护 ASP.NET 视图状态

ViewState 属性为在相同页面的多个请求之间保持状态值而提供了一个字典对象。这是 Web 页面用来在回传过程之间保持页面和控件属性值的默认方式。

在页面被处理的时候,页面和控件的当前状态会被编码,并且结果字符串会被保存成页面的一个隐藏字段。如果存储在 ViewState 属性中的数据的数量超出了在 MaxPageStateFieldLength 属性中被指定的上限,那么该字符串将被保存到页面的多个隐藏字段中。在页面被回传到服务器的时候,页面会在初始化过程中对视图状态字符串进行处理并恢复属性信息。

本文最佳实践中所描述的信息将对有助于保护被存储在视图状态中的应用程序数据。

虽然如下代码和最佳配置实践能够改进应用程序的安全性,但是频繁地保持 Web 服务器计算机中 Microsoft Windows 和 Internet 信息服务(IIS)的最新安全更新也是同样重要的,包括 Microsoft SQL Server 或其他成员资格数据源的任何安全更新。

关于更多编写安全代码和保护应用程序的最佳实践的详细内容能够在由 Michael Howard 和 David LeBlanc 共同编著的《编写安全代码》一书中找到,或者也可以参考 Microsoft Patterns 和实践所提供的指导。

保护页面中的状态视图数据

默认时,视图状态数据被存储在页面的隐藏字段中,并且转换成基于 64 位的编码。另外,还会创建一个使用机器验证码(MAC)作为关键字的散列值。散列值被添加在已编码的视图状态数据中,而结果字符串则被存储在页面中。在页面朝服务器回传的时候,ASP.NET 页面框架会重新生成视图状态数据的散列值,并与先前被存储在页面中的散列值进行比较。如果两个散列值无法匹配,那么将会引发一个异常并指示视图状态数据已经失效。

通过创建散列值,ASP.NET 页面框架能够测试视图状态数据是否已经被篡改。但是视图状态数据仍然能够被查看到,并且能够潜在地被恶意用户截获并读取。

MAC 编码

在 ASP.NET 页面框架为视图状态数据创建散列值的时候,它会使用在 Machine.config 文件中被自动生成或被指定的 MAC 关键字。如果该关键字是被自动生成的,它将基于计算机的 MAC 地址而被创建。MAC 地址是计算机网络适配器中唯一的 GUID 值。

应用 MAC 编码对于恶意用户针对基于视图状态值的 MAC 关键字所进行的反向工程来说是比较困难的。因此,MAC 编码通常在检测是否有人对视图状态数据进行篡改的时候是一种可靠的方式。

通常,在使用更大的 MAC 关键字来生成散列值的时候,最起码的可能就是由不同的字符串所生成的散列值都将会是相同的。在关键字被自动生成的时候,ASP.NET 使用会使用 SHA1 编码来创建一个更大的关键字。但是,在 Web 农场环境中,关键字必须在所有服务器中都保持一致。如果关键字不相同,同时页面被回传到创建该页面的服务器之外的另外一个不同的服务器,那么 ASP.NET 页面框架将会引发一个异常。因此,在 Web 农场环境中,你应该在 Machine.config 文件中指定一个关键字来代替在 ASP.NET 中自动生成的关键字。关键字越长,它所需要的安全性就越高;但是超长的关键字却经常被用来创建散列值,所以对于它来说,安全性需求永远要比性能需求更加重要。

加密

虽然 MAC 编码能够有助于防止视图状态数据不被篡改,但是它仍然不能够防止用户对数据的查看。视图状态数据被存储在页面的若干隐藏字段中,并且被应用了基于 64 位的编码。你能够使用两种方式来防止用户查看这些数据:通过 SSL 来传输页面和对视图状态数据进行加密。需要通过 SSL 而发送的页面能够有助于防止那些不打算接收页面的人对数据包进行嗅探并对非授权的数据进行访问。

但是,因为 SSL 会对页面进行解密并显示在浏览器中,所以视图状态数据仍然能够被查看到。在你需要针对不允许查看页面的人以及能够访问视图状态数据的未授权用户而对数据进行保护的时候,这样做是有好处的。但是,在某些情况下的控件可能会使用视图状态来存储一些禁止任何用户进行访问的信息。例如,页面可能包含一个在视图状态中存储子项标识符(数据关键字)的数据绑定控件。如果这些标识符包含机密数据(如消费者 ID 的交易安全编号),那么你还应该另外对视图状态数据进行加密或者干脆使用 SSL 来进行发送。

要加密数据,就需要先把页面的 ViewStateEncryptionMode 属性值设置为 true。如果你在视图状态中存储了信息,那么你就能够进行常规的读写操作;页面会自动为你完成所有的加密与解密任务。加密视图状态能够影响到应用程序的性能,所以仅在必需的使用前提下才考虑对其进行使用。

控件状态的加密

Web 控件能够维护少量的数据,这些数据被称之为控件的状态,控件状态是控件的正常运作所必需的。在控件使用了控件状态的时候,一个包含该控件状态的视图状态字段会在每次请求发生的时候都被发送到客户端,即使在应用程序或页面的视图状态被关闭的情况下也是如此。

使用控件状态的控件可以通过调用 RegisterRequiresViewStateEncryption 方法来加密视图状态。只要页面中有任何一个控件要求对视图状态进行加密,那么页面中所有的视图状态也都将被加密。

每用户视图状态的加密

如果你的 Web 网站能够鉴别用户,那么你可以在 Page_Init 事件处理器中设置 ViewStateUserKey 属性把页面的视图状态与特定的用户相关联。这有助于防止“点击式攻击”(注:即恶意用户会创建一个有效的、预填充的 Web 页面,页面中包含有来自于先前被创建页面的视图状态。然后攻击者会诱导受害人单击一个能够使用受害人的身份把页面发送到服务器的链接)。

ViewStateUserKey 属性的值被设置的时候,攻击者的身份就被用来创建原始页面中视图状态的散列值。在受害人再次被诱导并重新发送该页面的时候,因为用户关键字的不同,所以散列值也将变得不一样。那么页面将出现验证错误并抛出一个异常。

你必须为每个用户都设置唯一的 ViewStateUserKey 属性值(如用户名称或标识符)。

在已共享的托管环境中保护配置

在已共享的托管环境中,通过直接更改 Machine.config 文件、或通过更改配置 API、或通过其他管理工具和配置工具,恶意用户就能够潜在地对可能影响计算机中其他应用程序的状态管理的属性集进行更改。要防止对应用程序配置所作的更改,你可以对配置文件的配置段进行加密。关于更多信息,请参考:[使用已保护的配置对配置信息进行加密]。

你可能感兴趣的:(asp.net)