购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.5 保护视图数据

视图状态是每一个主流Web开发语言都有的技术,允许页面在回传时保持表单属性。每一次提交页面都可以获得所有表单控件的当前状态,并且将它们作为编码字符串存储在一个隐藏的表单字段中。视图状态的风险是攻击者能够查看或修改这些表单值,以实现攻击。

为了防范类似的攻击,诸如JSP或ASP.NET都允许使用加密来保护视图状态数据,并用哈希算法检测恶意修改。

视图状态的安全主要通过以下5种方式进行保护:

1.保证视图状态哈希值

视图状态数据存储在页面上的隐藏字段中,使用Base64编码机制进行编码,并使用计算机身份验证代码密钥从视图状态数据中创建这些数据的哈希。该哈希值会添加到编码的视图状态数据中,并且生成的字符串会存储在页面中。当页面被回传到服务器时,ASP.NET框架会重新计算哈希值,并将其与视图状态中存储的值进行比较。如果哈希值不匹配,将引发异常,指示视图状态数据可能无效。

通过创建哈希值,ASP.NET框架可以测试视图状态数据是否已被损坏或篡改。但是,即使视图状态数据未被篡改,这些数据仍然可能被恶意用户截获和读取。

2.使用MAC密钥计算视图状态哈希值

用于计算视图状态哈希值的MAC密钥可以自动生成,也可以在Machine.config文件中指定。如果该密钥自动生成,则基于计算机的MAC地址(它是该计算机中网络适配器的唯一GUID值)进行创建。

恶意用户很难根据视图状态中的哈希值进行反向工程处理以推断出MAC密钥。因此,MAC编码是一种用来确定视图状态数据是否已更改的可靠方式。

通常用于生成哈希的MAC密钥越大,不同字符串的哈希值相同的可能性就越小。如果密钥是自动生成的,则ASP.NET使用SHA1编码来创建一个大型密钥。不过,在网络场环境中,所有服务器的密钥必须相同。如果密钥不同,那么当页面回传至创建该页的服务器之外的其他服务器时,ASP.NET页框架将引发异常。

因此,在网络场环境中,应在Machine.config文件中指定密钥,而不是让ASP.NET自动生成。这种情况下应确保创建的密钥足够长,以便使哈希值具有充分的安全性。但是,密钥越长,创建哈希所需要的时间也就越多。因此,必须在安全需求与性能需求之间进行权衡。

3.视图状态加密

虽然MAC编码有助于防止篡改视图状态数据,但这种编码也会妨碍用户查看数据。可以通过下面两种方式来防止他人查看此数据:通过SSL传输页面和加密视图状态数据。要求通过SSL发送页面有助于防止那些原本不应该收到该页面的人探查数据包和未经授权访问数据。

但是,请求页面的用户仍然能够查看视图状态数据,因为SSL会解密页面以便在浏览器中进行显示。如果不担心视图加密的信息被认证用户查看,则可以使用。但在某些情况下,控件可能会使用视图状态存储任何用户都不应访问的信息。

例如,请求页面中可能包含一个数据绑定控件,该控件存储视图状态的项标识符(数据密钥)。如果这些标识符中包含敏感数据(如客户ID),则应对视图状态数据进行加密来替代通过SSL发送页面,或是将其作为通过SSL发送页面的补充方法。

若要加密数据,页面的ViewStateEncryptionMode属性应设置为true。在视图状态中存储信息时,可以使用常规的读写技术。该页面会为使用者处理所有加密和解密工作。对视图状态数据进行加密可能会影响应用程序的性能。

4.控件状态加密

通过调用RegisterRequiresViewStateEncryption方法对视图状态加密。如果页面中的任何控件都要求对视图状态进行加密,则该页面中的所有视图状态都会进行加密。

5.基于每个用户的视图状态编码

如果网站需要对用户进行身份验证,则可以设置Page_Init事件处理程序中的ViewStateUserKey属性,以便将页面的视图状态与特定用户相关联。这将有助于防止一键式(one-click)攻击。攻击者随后引诱受害者单击一个链接,该链接使用受害者的标识向服务器发送页面。

如果设置了ViewStateUserKey属性,将使用攻击者的标识来创建原始页面的视图状态的哈希。受害者被引诱重新发送此页面时,由于用户密钥不同,因此哈希值也将不同。这样,页面的验证将失败,并且引发一个异常。

必须将ViewStateUserKey属性与每个用户的一个唯一值(如用户名或标识符)相关联。下面我们对其中的几种重要方式作详细说明。

4.5.1 开启视图保护开关

开发人员通过设置参数可以在机器、应用程序、页面或控件级别上启用视图状态。作为开发人员希望为整个系统启用视图状态,但同时也希望有更多灵活的选择,以减少暴露给攻击的风险。

表4-3所示为在各种级别中使用不同的配置参数。

表4-3 配置选项

熟悉视图的开发人员都知道视图是未加密的,它仅仅使用了base 64编码方式。可以使用ViewState Decoder工具以图形化的方式解码和查看数据。

以ViewState Decoder工具为例,黑客只需将获取的视图数据复制到左边的文本框内容,在右边即可显示视图所表达的控件状态和原始数据。数据还原结果如图4-3所示。

图4-3 窥探视图数据

视图状态表示表单的控件属性,所以攻击者能够通过修改视图状态属性来改动表单。例如,攻击者可以改变在线购物车上的产品价格,或者修改参数以执行SQL注入攻击。攻击者可能会尝试许多其他类型的攻击,如跨站点脚本、未授权文件访问或缓存溢出等。

为了防止攻击者操纵视图状态,可以使用一个消息验证代码(MAC)。MAC实质上是一个确保其完整性的数据哈希,可以在机器、应用程序或页面级别上启用视图状态MAC。

启用了MAC检查时(默认情况),将对序列化的视图状态附加一个哈希值,该值是使用某些服务器端值和视图状态用户密钥(如果有)生成的。回传视图状态时,将使用新的服务器端值重新计算该哈希值,并将其与存储的值进行比较。如果两者匹配,则允许请求;否则将引发异常。

即使假设黑客具有破解和重新生成视图状态的能力,他仍需要知道服务器存储的值才可以得出有效的哈希。具体说来,该黑客需要知道machine.config的<machineKey>项中引用的计算机密钥。

服务器默认情况下是自动生成的,以物理方式存储在LSA(Windows Local Security Authority)中。仅在Web(此时视图状态的计算机密钥必须在所有的计算机上都相同)的情形下,才应当在machine.config文件中将其指定为明文。

视图状态MAC检查是通过名为EnableViewStateMac的@Page指令属性控制的。如前所述,默认情况下,它被设置为true。笔者建议永远不要禁用它;否则将会使视图状态篡改攻击成为可能,并具有很高的成功概率。

EnableViewStateMac验证流程如图4-4所示。

图4-4 EnableViewStateMac验证流程

MAC可防止某些人随意修改视图状态数据,如果MAC不匹配则废弃其内容。然而,仍然可以使用前面提及的ViewState Decoder工具来解码并查看视图状态的内容。为了克服这个问题,可以加密视图状态字段的内容,使用machine.config文件中的machineKey元素配置这种加密。

下面的代码示例演示如何将验证字段validationKey和密钥字段decryptionKey属性都设置为自动生成AutoGenerate。并且,指定isolateApps值,以便为服务器上的每个应用程序生成一个唯一的密钥。

MAC机器密钥配置XML代码如下:

上述加密验证的类型属性设置为SHA1,也可以替换成MD5或3DES。前两个加密算法属性使ASP.NET创建MD5或SHA-1 MAC哈希,而3DES则加密视图状态内容并创建SHA-1 MAC。将验证有效性的模式设置为3DES,可保护数据不被查看,并且防止参数操纵的攻击。但是,这仍然无法使视图状态彻底安全。攻击者可以预先填写表单,保存视图状态字段,然后欺骗另一个用户使用该表单。为了防止这种类型的攻击,ASP.NET允许为每个用户设置一个独特的密钥,使视图状态数据只对该用户有效,在page_init事件中设置page对象的ViewStateUserKey属性。对于经过验证的用户,可以将该属性设置为用户的名称或会话ID。对于匿名的用户,应该创建一个随机数,并且将其保存在用户的Cookie中。

4.5.2 加密视图信息

除了设置视图参数之外,如何加密也是保护视图数据的关键。.NET技术使用Page.RegisterRequiresViewStateEncryption方法将控件注册为需要视图状态加密的控件。

当开发人员需要研发用于处理潜在的敏感信息的自定义控件,则必须启用RegisterRequiresViewStateEncryption方法向页面注册控件,以确保该控件的视图状态信息已加密。

加密之前需要设置加密模式,属性名是ViewStateEncryptionMode。通过设置获取或设置视图状态的加密模式,加密行为可以自动完成。

在实际开发中,很多开发人员喜欢直接从数据库获取数据源并且绑定到数据表控件。这种方法在Java或ASP.NET等技术中广泛运用。但这样的做法存在不安全的因素,会为黑客提供一些用户的操作数据,这是非常危险的。

下面的实例说明如何为Page对象设置视图状态加密模式并通过RegisterRequiresViewStateEncryption加密视图状态。该实例最终结果是使从数据库获取数据的同时,将它们在显示控件的视图中加密。

实例代码如下:

加密后的文本控件仍然能够正常的显示数据,但是在黑客查看HTML代码时,视图数据已经被散列加密了,类似如下的HTML代码:

4.5.3 用户独立视图

用户独立视图的出现,标志着Web系统能够根据不同用户的访问请求做出不同的响应动作。Java或.NET框架都引入类似ViewStateUserKey的技术来实现独立视图功能,把页面相关联的视图状态变量中一个标识符分配给单个用户。

用户独立视图提供了附加的输入以创建防止视图状态被篡改的哈希值,有效防止黑客攻击。换句话说,ViewStateUserKey使得黑客使用客户端视图状态的内容来准备针对站点的恶意张贴困难了许多。可以为该属性分配任何非空的字符串,但最好是会话ID或用户ID。

类似的黑客攻击将恶意的HTTP表单提交到等待表单的页面。页面将使用张贴来的数据执行某些敏感操作。攻击者了解如何使用各个域,并想出一些虚假值来达到目的。这通常是目标特定的攻击,而且由于它所建立的三角关系,很难追本溯源导致恶意代码被张贴到第三个站点,事实上形成了跨站点攻击,如图4-5所示。

图4-5 冒名攻击流程

冒名攻击要想得手,黑客必须能够访问该页面,此时黑客会在本地保存该页面。这样就可以访问_VIEWSTATE域并使用该域,用旧的视图状态和其他域中的恶意值创建请求。

设置ViewStateUserKey属性有助于防止应用程序受到恶意用户的点击式攻击。具体实现方式是,允许开发人员为各个用户的视图状态变量分配一个标识符,使他们不能使用该变量来生成点击式攻击。

所有用户将ViewStateUserKey设置为常量字符串,相当于将它保留为空。开发人员必须将它设置为对各个用户都不同的值。由于一些技术和社会原因,会话ID更为合适,因为会话ID不可预测,会超时失效,并且对于每个用户来说都是不同的。

以下代码实例将通过会话编号标示用户的唯一身份,并在页面初始化时被执行:

为了避免重复编写这些代码,读者可以将它们固定在从Page派生的类的OnInit虚拟方法中(请注意必须在Page.Init事件中设置此属性): 8thn8AV2Ep1025yK33LfVS1GkJvBbTS/bkO5OAJH7gj/rkEOD1XHZ1Y/I1Z8iDEf

点击中间区域
呼出菜单
上一章
目录
下一章
×