ViewState 到底是什么?ViewState 用于维护页面的 UI 状态。Web 是没有状态的,ASP.NET 页面也没有状态,它们在到服务器的每个往返过程中被实例化、执行、呈现和处理。在 ASP.NET 之前,通过多次回传将值恢复到窗体字段中完全是页面开发人员的责任,他们将不得不从 HTTP 窗体中逐个拾取回传值,然后再将其推回字段中。幸运的是,现在 ASP.NET 可以自动完成这项任务,从而为开发人员免除了一项令人厌烦的工作,同时也无需再为窗体编写大量的代码。但这并不是 ViewState。

ViewState是一种机制,ASP.NET 使用这种机制来跟踪服务器控件状态值,否则这些值将不作为 HTTP 窗体的一部分而回传。例如,由 Label 控件显示的文本默认情况下就保存在 ViewState 中。作为开发人员,您可以绑定数据,或在首次加载该页面时仅对 Label 编程设置一次,在后续的回传中,该标签文本将自动从 ViewState 中重新填充。因此,除了可以减少繁琐的工作和代码外,ViewState 通常还可以减少数据库的往返次数。

ViewState 的工作原理

ViewState 确实没有什么神秘之处,它是由 ASP.NET 页面框架管理的一个隐藏的窗体字段。当 ASP.NET 执行某个页面时,该页面上的 ViewState 值和所有控件将被收集并格式化成一个编码字符串,然后被分配给隐藏窗体字段的值属性(即 <input type=hidden>)。由于隐藏窗体字段是发送到客户端的页面的一部分,所以 ViewState 值被临时存储在客户端的浏览器中。如果客户端选择将该页面回传给服务器,则 ViewState 字符串也将被回传。

关于 ViewState 还有三个值得注意的小问题

1、如果要使用 ViewState,则在 ASPX 页面中必须有一个服务器端窗体标记 (<form runat=server>)。窗体字段是必需的,这样包含 ViewState 信息的隐藏字段才能回传给服务器。而且,该窗体还必须是服务器端的窗体,这样在服务器上执行该页面时,ASP.NET 页面框架才能添加隐藏的字段。

2、页面本身将 20 字节左右的信息保存在 ViewState 中,用于在回传时将 PostBack 数据和 ViewState 值分发给正确的控件。因此,即使该页面或应用程序禁用了 ViewState,仍可以在 ViewState 中看到少量的剩余字节。

3、在页面不回传的情况下,可以通过省略服务器端的 <form> 标记来去除页面中的 ViewState。

设定ViewState的值

ViewState中部分值是可以通过代码的形式显示设置或调用的,使用的编程语法和高速缓存的语法类似。

//保存在ViewState中

ViewState["yourName"] = "Leopold";

//从 ViewState 中读取

string yourName = (string)ViewState["SortOrder"];

ViewState安全吗?

由于 ViewState 没有被格式化为清晰的文本,某些人有时会认为它被加密了,其实并没有。相反,ViewState 只是进行了 Base64 编码,以确保值在往返过程中不会发生变化,而并不考虑应用程序使用的响应/请求编码。

ViewState在Render事件前在Page.SavePageStateToPersistenceMedium方法中保存,

//ViewState Saved in Session State

protected override object LoadPageStateFromPersistenceMedium() {

return Session["ViewState"];

}

protected override void SavePageStateToPersistenceMedium(object viewState) {

Session["ViewState"] = viewState;

// Bug requires Hidden Form Field __VIEWSTATE

RegisterHiddenField("__VIEWSTATE", "");

}

并在PostBack时通过Page.LoadPageStateFromPerSistenceMedium方法恢复。

protected override object LoadPageStateFromPersistenceMedium() {

LosFormatter format = new LosFormatter();

return format.Deserialize(YourDataStore["ViewState"]);

}

protected override void SavePageStateToPersistenceMedium(object viewState) {

LosFormatter format = new LosFormatter();

StringWriter writer = new StringWriter();

format.Serialize(writer, viewState);

YourDataStore["ViewState"] = writer.ToString();

}

通过继承两个方法可以很容易地将ViewState保存到Session中,这在低带宽网络环境下可以减少网络流量。现在完全出于兴趣地来看下ViewState的内在结构。每个ViewState在Triplet(System.Web.UI.Triplet)中保存,其中第一个对象是System.Web.UI.Pair,第二个对象是一个以树目录形式保存子控件的数组,第三个对象是以数组保存的与那些子控件相关的Triplets。这些都很难用语言来解释清楚,还是看下例子吧。

//Encoded ViewState:

dDwxMjM0NTY3ODkwO3Q8cDxsPHBycEE7cHJwQjtwcnBDOz47bDx2YWxBO3ZhbEI7dmFsQzs+PjtsPGk8

MD47aTwyPjtpPDM+O2k8NT47PjtsPHQ8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+O3Q8

cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+O3Q8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2

YWxCOz4+Ozs+O3Q8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+Oz4+Oz4=

//Decoded ViewState:

t<1234567890;t<p<l<prpA;prpB;prpC;>;l<valA;valB;valC;>>;

l<i<0>;i<2>;i<3>;i<5>;>;l<

t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;

t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;

t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;

t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;>>;>

解析用代码:

protected override void SavePageStateToPersistenceMedium(object viewState) {

// Call Base Method to Not Change Normal Process

base.SavePageStateToPersistenceMedium(viewState);

// Retrieve ViewState and Write Out to Page

LosFormatter format = new LosFormatter();

StringWriter writer = new StringWriter();

format.Serialize(writer, viewState);

string vsRaw = writer.ToString();

Response.Write("ViewState Raw: " + Server.HtmlEncode(vsRaw));

// Decode ViewState and Write Out to Page

byte[] buffer = Convert.FromBase64String(vsRaw);

string vsText = Encoding.ASCII.GetString(buffer);

Response.Write("ViewState Text: " + Server.HtmlEncode(vsText));

// Parse ViewState -- Turn On Page Tracing

ParseViewState(viewState, 0);

}

private void ParseViewState(object vs, int level) {

if (vs == null) {

Trace.Warn(level.ToString(), Spaces(level) + "null");

}

else if (vs.GetType() == typeof(System.Web.UI.Triplet)) {

Trace.Warn(level.ToString(), Spaces(level) + "Triplet");

ParseViewState((Triplet) vs, level);

}

else if (vs.GetType() == typeof(System.Web.UI.Pair)) {

Trace.Warn(level.ToString(), Spaces(level) + "Pair");

ParseViewState((Pair) vs, level);

}

else if (vs.GetType() == typeof(System.Collections.ArrayList)) {

Trace.Warn(level.ToString(), Spaces(level) + "ArrayList");

ParseViewState((IEnumerable) vs, level);

}

else if (vs.GetType().IsArray) {

Trace.Warn(level.ToString(), Spaces(level) + "Array");

ParseViewState((IEnumerable) vs, level);

}

else if (vs.GetType() == typeof(System.String)) {

Trace.Warn(level.ToString(), Spaces(level) + "'" + vs.ToString() + "'");

}

else if (vs.GetType().IsPrimitive) {

Trace.Warn(level.ToString(), Spaces(level) + vs.ToString());

}

else {

Trace.Warn(level.ToString(), Spaces(level) + vs.GetType().ToString());

}

}

private void ParseViewState(Triplet vs, int level) {

ParseViewState(vs.First, level + 1);

ParseViewState(vs.Second, level + 1);

ParseViewState(vs.Third, level + 1);

}

private void ParseViewState(Pair vs, int level) {

ParseViewState(vs.First, level + 1);

ParseViewState(vs.Second, level + 1);

}

private void ParseViewState(IEnumerable vs, int level) {

foreach (object item in vs) {

ParseViewState(item, level + 1);

}

}

private string Spaces(int count) {

string spaces = "";

for (int index = 0; index < count; index++) {

spaces += "   ";

}

return spaces;

}

对这些代码,还没有亲自验证过,资料来的已经比较早,好像Microsoft已经打过补丁了。不过网上还是能找到Decode ViewState的工具来解析ViewState。试了一下内部的站点,大多是解析失败的,但还是找到了一个现成的案例BS2Portal

BS2Portal,找到_ViewState

在工具中输入BS2Portal地址,Extract 一下,如果成功,ViewState String 中显示ISVIEW,然后再ViewState 输入_ViewState值,Decode一下就能看到ViewState 中的值了。

如何让ViewState更安全

可以向应用程序中添加两种 ViewState 安全级别:

防篡改

加密

防篡改

尽管散列代码不能确保 ViewState 字段中实际数据的安全,但它能够显著降低有人通过 ViewState 骗过应用程序的可能性,即防止回传应用程序通常禁止用户输入的值。

可以通过设置 EnableViewStateMAC 属性来指示 ASP.NET 向 ViewState 字段中追加一个散列代码:

%@Page EnableViewStateMAC=true %

可以在页面级别上设置 EnableViewStateMAC,也可以在应用程序级别上设置。在回传时,ASP.NET 将为 ViewState 数据生成一个散列代码,并将其与存储在回传值中的散列代码进行比较。如果两处的散列代码不匹配,该 ViewState 数据将被丢弃,同时控件将恢复为原来的设置。

默认情况下,ASP.NET 使用 SHA1 算法来生成 ViewState 散列代码。此外,也可以通过在 machine.config 文件中设置 <machineKey> 来选择 MD5 算法,如下所示:

<machineKey validation="MD5" />

加密

可以使用加密来保护 ViewState 字段中的实际数据值。首先,必须如上所述设置 EnableViewStatMAC="true"。然后,将 machineKey validation 类型设置为 3DES。这将指示 ASP.NET 使用 Triple DES 对称加密算法来加密 ViewState 值。

<machineKey validation="3DES" />

Web 领域中的 ViewState 安全性

默认情况下,ASP.NET 将创建一个随机的验证密钥,并存储在每个服务器的本地安全授权 (LSA) 中。要验证在另一台服务器上创建的 ViewState 字段,两台服务器的 validationKey 必须设置为相同的值。如果要通过上述方式之一,对运行于 Web 领域配置中的应用程序进行 ViewState 安全设置,则需要为所有服务器提供一个唯一的、共享的验证密钥。

验证密钥是一个包含 20 到 64 位密码增强字节的随机字符串,用 40 到 128 个十六进制字符表示。密钥越长越安全,因此建议使用 128 个字符的密钥(如果计算机支持)。例如:

<machineKey validation="SHA1" validationKey="

F3690E7A3143C185AB1089616A8B4D81FD55DD7A69EEAA3B32A6AE813ECEECD28DEA66A

23BEE42193729BD48595EBAFE2C2E765BE77E006330BC3B1392D7C73F" />

System.Security.Cryptography 名称空间包括 RNGCryptoServiceProvider 类,使用该类可以生成此字符串,如以下 GenerateCryptoKey.aspx 示例所示:

<%@ Page Language="c#" %>

<%@ Import Namespace="System.Security.Cryptography" %>

<HTML>

<body>

<form runat="server">

<H3>生成随机加密密钥</H3>

<P>

<asp:RadioButtonList id="RadioButtonList1"

runat="server" RepeatDirection="Horizontal">

<asp:ListItem Value="40">40-byte</asp:ListItem>

<asp:ListItem Value="128" Selected="True">128-byte</asp:ListItem>

</asp:RadioButtonList>&nbsp;

<asp:Button id="Button1" runat="server" οnclick="GenerateKey"

Text="生成密钥">

</asp:Button></P>

<P>

<asp:TextBox id="TextBox1" runat="server" TextMode="MultiLine"

Rows="10" Columns="70" BackColor="#EEEEEE" EnableViewState="False">

复制并粘贴生成的结果</asp:TextBox></P>

</form>

</body>

</HTML>

<script runat=server>

void GenerateKey(object sender, System.EventArgs e)

{

int keylength = Int32.Parse(RadioButtonList1.SelectedItem.Value);

// 在此处放入用于初始化页面的用户代码

byte[] buff = new Byte[keylength/2];

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

// 该数组已使用密码增强的随机字节进行填充

rng.GetBytes(buff);

StringBuilder sb = new StringBuilder(keylength);

int i;

for (i = 0; i < buff.Length; i++) {

sb.Append(String.Format("{0:X2}",buff[i]));

}

// 粘贴到文本框,用户可从中复制

TextBox1.Text = sb.ToString();

}

</script>

欢迎讨论

参考文献 :

1   Susan Warren   ‘ASP.NET ViewState 初探’ China MSDN 11/2001

2   Kaneboy's Blog ‘View State’              15/16/2004

3   Paul Wilson      'ViewState: All You Wanted to Know'    11/2/2006

转载于:https://www.cnblogs.com/OliveSky/archive/2008/08/16/1269284.html

ViewState 安全初探相关推荐

  1. Asp.Net基础 - 4.ASP.Net揭秘之Input版自增 + 5.ViewState初探

    4.ASP.Net揭秘之Input版自增 4.2.思考:把IntValue1.html设为起始页 5.ViewState初探 5.1.只有设定了name的input.textarea.select的v ...

  2. ASP.NET ViewState 初探

    Susan Warren Microsoft Corporation 与刚接触 ASP.NET 页面的开发人员交谈时,他们通常向我提出的第一个问题就是:"那个 ViewState 到底是什么 ...

  3. Asp.Net中的ViewState知识

    ASP.NET ViewState 初探 http://www.microsoft.com/china/msdn/archives/library/dnaspnet/html/Asp11222001. ...

  4. ASP.Net学习笔记014--ViewState初探3

    ASP.Net学习笔记014--ViewState初探3 为什么禁用了viewstate,还能修改label2的值 因为:viewstate只是记录label2的值,并不影响给label2进行设置 - ...

  5. ASP.Net学习笔记013--ViewState初探2

    ASP.Net学习笔记013--ViewState初探2 上课讲的viewstate,由于需要跟后台服务器进行传值,需要封装很多隐藏列,比如100条数据,就会有100个viewstate 如果用在一些 ...

  6. 从viewState说开去

    一个简单的启用了VIEWSTATE的DATAGRID竟然将我的页面增肥了5K左右,曾经一度让我对asp.net充满怀疑.可是想想,我是可以自己决定是不是使用VIEWSTATE的,我可以自己定义我的事件 ...

  7. Asp.net ViewState

    1.基本比較                                 session                     viewState サーバ資源使用                 ...

  8. Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用

    一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...

  9. 2021年大数据Flink(九):Flink原理初探

    Flink原理初探 Flink角色分工 在实际生产中,Flink 都是以集群在运行,在运行的过程中包含了两类进程. JobManager: 它扮演的是集群管理者的角色,负责调度任务.协调 checkp ...

最新文章

  1. 错误解决记录------------mysql连接本地数据库显示can't get hostname for your address
  2. 初中文化能学编程吗_儿童早教益智,乐森星际特工智能编程机器人体验
  3. crontab linux
  4. 乐山市计算机学校欺骗,据说这个学校很乱。
  5. Navicat连接MySQL8.0版本时出现Client does not support authentication protocol requested by server;报错的问题解决办法
  6. LintCode 412: Candy
  7. NC单点登录设置默认界面
  8. 淘宝为什么有的人月销量上万,他们是怎么操作的?
  9. 深海迷航代码_《深海迷航(Subnautica)》入坑指南
  10. 这款耳机亲测,性价比堪比 AirPods
  11. java实现lbs_Java总结篇系列:Java泛型
  12. Python3.6笔记之腌制泡菜(pickle模块的用法)
  13. HGE编写游戏的心得体会
  14. Magento 数据库EVA
  15. GoogLeNet: Going deeper with convolutions
  16. Pikachu靶场-SQL注入-搜索型注入过关步骤
  17. JS学习之求带参函数求任意两个数和
  18. 计算机初级考试题库网络管理,计算机基础考试题库(含答案)【精】.doc
  19. 超市端午节促销活动方案
  20. APP收款语音播报功能讲解

热门文章

  1. HTML、CSS与JS实现简易iPhone计算器
  2. pig基本语法——cross
  3. 【渝粤题库】国家开放大学2021春2321物流学概论答案
  4. Cocos2d-x之多分辨率屏幕适配
  5. 结构体内部申请空间_智能体张量融合,一种保持空间结构信息的轨迹预测方法...
  6. TUM RGBD数据集工具及使用
  7. 51单片机通过两片74HC595级联,用8位LED数码管,分别显示当前日期,如:“2”、“0”、“-”、“0”、“5”、“-”、“2”、“6”,用Proteus仿真实现。
  8. makop勒索病毒|勒索病毒解密|勒索病毒恢复|数据库修复
  9. 初学做网站的草根站长必读
  10. MFC设置背景图片之三(使用GDI+)