前言

1. FineUI(开源版)是完整开源,最早发起于 2008-04,下载全部源代码:http://fineui.codeplex.com/

2. 你可以通过捐赠作者来支持FineUI(开源版)的发展:http://fineui.com/donate/

FineUI的FState与ViewState

早在2013-01 我曾写过一篇文章,对FState有详细介绍:http://www.cnblogs.com/sanshi/archive/2013/01/08/2850459.html

现在来简要回顾一下:

1. ViewState是ASP.NET WebForm的基石,用来在页面回发过程中维持控件状态,这样我们才能在后台方便的使用控件的服务器端属性。

2. FineUI的AJAX回发过程中,相同的数据会同时存在于ViewState和返回的JavaScript代码中,造成数据重复浪费!

3. FState机制替换ViewState后,只会在回发数据中保留一份数据,减少了数据的传输量。

对于,常见的误解与纠正:

1. FineUI中不能使用ViewState了。错!!

FineUI只是实现了一套类似ViewState的机制,但是ViewState本身还是存在的,你依然可以在页面上调用ViewState对象存储数据。

2. 不使用ViewState了,FineUI控件不能维持状态了。错!!

FState是在AJAX环境中对ViewState的一种改进和提高,目的是为了减少数据传输量。你依然可以方便在C#代码中使用控件属性

FineUI中的FState可以被恶意篡改

FState用来在页面回发过程中维持控件的状态,但是由于FState完全以JavaScript变量的形式暴露出来,很容易被恶意用户在客户端进行篡改。

首先来看一个简单的页面:

<f:PageManager ID="PageManager1" runat="server" />
<f:DropDownList runat="server" ID="DropDownList1">
<f:ListItem Text="可选项1" Value="Value1" Selected="true" />
<f:ListItem Text="可选项2" Value="Value2" />
<f:ListItem Text="可选项3" Value="Value3" />
</f:DropDownList>
<f:Button runat="server" Text="提交"
ID="btnSubmit" OnClick="btnSubmit_Click"></f:Button>

后台的按钮事件:

protected void btnSubmit_Click(object sender, EventArgs e)
{
Alert.Show("下拉列表选中项:" + DropDownList1.SelectedValue);
}

页面运行效果:

在页面生成的HTML代码,我们可以看到 f_state 的身影:

下面我们通过一个例子来讲解 FState 的作用,假如用户在前台对下拉列表的数据进行了重新绑定:

var ddl = F("DropDownList1");
var newdata = [
["Data1", "数据1", 1],
["Data2", "数据2", 1],
["Data3", "数据3", 1]
];
ddl.store.loadData(newdata);
ddl.setValue("Data1");

此时点击提交按钮,效果:

之所以后台取不到下拉列表的选中值,是因为后台从FState恢复了下拉列表的项分别是“选项一”,“选项二”和“选项三”。

而对于客户端重新绑定的新数据源,后台一无所知,因此拿新的选中项值 Data1 去检索时,自然就找不到对应的项了,所以此时SelectedValue==null

这个逻辑自然是正确的,但是由于 FState 是以JavaScript的形式返回到页面的,所以恶意用户自然就可以篡改这个值了:

var ddl = F("DropDownList1");
var newdata = [
["Data1", "数据1", 1],
["Data2", "数据2", 1],
["Data3", "数据3", 1]
]; ddl.f_state.F_Items = newdata;
ddl.store.loadData(newdata);
ddl.setValue("Data1");

此时再点击提交按钮:

此时服务器已经接受了这个客户端恶意篡改的值!!这个就不对了。

如果是文本输入框的值,我们自然是要手工进行服务器端验证的,不要相信客户端传入的任何值,因为都有可能被篡改!

但是如果能默认提供一种内置的验证机制,让这种恶意修改FState的行为消失,岂不是更好。FineUI v6.0对此进行了增强。

FineUI v6.0 中默认的FState服务器端验证

完全相同的例子,在 FineUI v6.0 中,如果通过客户端修改下拉列表的f_state和内部数据,此时提交按钮:

这个就是我们的保护机制,保护服务器端输出的FState信息不会在客户端被恶意修改。

那么这种保护机制是如何实现的呢?我们从生成的网页代码来分析一下:

可以看到,控件除了生成 f_state 属性,还额外附加了一个 f_state_v 属性,这个很容易理解为对 f_state 的加密值。

那么在页面回发时,只需要把这个 f_state_v 的值一块回发,后台进行解密验证即可。我们来看下HTTP请求的参数:

这里没有 f_state_v 的身影,那是因为他隐藏在 F_STATE 变量中的,这个值是 Base64 编码的,我们解码后看下:

{
"DropDownList1": [{
"F_Items": [
["Data1", "\u6570\u636e1", 1],
["Data2", "\u6570\u636e2", 1],
["Data3", "\u6570\u636e3", 1]
],
"SelectedValue": "Value1",
"SelectedValueArray": ["Value1"]
}, "e1ae24"]
}

可以看到,这个 f_state_v 的确一起回发到后台了。

这个逻辑其实并不复杂:

1. 页面初始化时,除了生成控件的 f_state 之外,还额外的生成一个加密后的信息 f_state_v

2. 页面回发时,后台把这两个值进行校验,就知道是否在客户端被修改了

3. 如果后台控件的属性发生变化,还重新生成 f_state_v 更新到前台

这里给出后台的主要逻辑代码,完整源代码请自行下载:

private static string GetFStateValidation(JObject stateObj)
{
string fstate = stateObj.ToString(Newtonsoft.Json.Formatting.None);
return GetShortMD5HashWithSeed(fstate);
} private static bool ValidateFState(JObject stateObj, string validationString)
{
string fstate = stateObj.ToString(Newtonsoft.Json.Formatting.None);
string fstateCode = GetShortMD5HashWithSeed(fstate); if (fstateCode == validationString)
{
return true;
}
else
{
return false;
}
} private static string GetShortMD5HashWithSeed(string fstate)
{
string md5HashStr = StringToMD5Hash(fstate + GetFStateValidationSeed());
return md5HashStr.Substring(, ) + md5HashStr.Substring(md5HashStr.Length - , );
} private static string StringToMD5Hash(string inputString)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] encryptedBytes = md5.ComputeHash(Encoding.ASCII.GetBytes(inputString));
string a = System.Text.Encoding.Default.GetString(encryptedBytes); StringBuilder sb = new StringBuilder();
for (int i = ; i < encryptedBytes.Length; i++)
{
sb.AppendFormat("{0:x2}", encryptedBytes[i]);
}
return sb.ToString();
} private static string _fstateValidationSeed = String.Empty;
private static string GetFStateValidationSeed()
{
if (String.IsNullOrEmpty(_fstateValidationSeed))
{
_fstateValidationSeed = new Guid().ToString();
}
return _fstateValidationSeed;
}

小结

这篇文章讲解了FineUI中的FState取代ViewState的原因,恶意用户如何在客户端篡改FState,然后介绍了FineUI v6.0对 FState 的保护机制。

然后我们从生成的页面HTML入手,简要分析了FState验证机制的实现原理。

感兴趣的朋友可以自行下载源代码分析:http://fineui.codeplex.com/

关于开源和坚持

FineUI(开源版)开始于 2008-04,8年多时间内,我们坚持更新了 128 个版本,内部使用的 extjs 从最初的 v2.x,v3.x,到后来的v4.x,FineUI v6.0 使用了最新的extjs v6.2.0。

8 年间,我们看过太多的开源项目轰轰烈烈的来,平平淡淡的去,那些曾经熟悉的身影,曾经陪伴我们的代码,都已经不复存在。其实很多时候,开源项目不是被新技术淘汰,而是被开源作者所丢弃,不免让人扼腕叹息。

每个存在都有存在的价值,时间总会让之前的东西看起来不再那么新奇好玩,但是还有那么一帮曾经关注的网友,一直在使用的用户,只有不断的更新,才不会让关心你的人失望。

任何事物的存在价值是无限的!

FineUI(开源版)v6.0中FState服务器端验证的实现原理的更多相关文章

  1. AppBox v6.0中实现子页面和父页面的复杂交互

    前言 1. AppBox是捐赠开源(获取源代码至少需要捐赠作者 1 元钱),基于的 FineUI(开源版)则是完整开源,网址:http://fineui.codeplex.com/ 2. 你可以通过捐 ...

  2. FineUI开源版之TreeGrid实现

    FineUI开源版是没有树表格的,但是又需要,怎么办呢?在博客园看到一位大大的文章 http://www.cnblogs.com/shiworkyue/p/4211002.html 然后参考,不知道为 ...

  3. FineUI开源版(ASP.Net)初学手册

    女朋友鄙视我原创少... 1.下载 进入官方论坛:http://www.fineui.com/bbs/ 要用到下载源代码和空项目下载 http://fineui.codeplex.com/ http: ...

  4. (十六)客户端验证与struts2中的服务器端验证

    一.客户端验证: 即用javaScript来验证. <%@ page language="java" contentType="text/html; charset ...

  5. FineUI开源版之TreeGrid(修改)

    上篇文章中做了简单实现,但是还是有bug的,还需要在外面写事件的处理,今天又进行修改了. 下面放出代码,同样的  hzh modify标记的就是我进行修改的地方 grid.cs 添加代码 #regio ...

  6. FineUI开源版(ASP.Net)初学手册-部分JS整理

    有人老找JS,我吧FineUI自己写的JS沾过来方便大家看看,在实现前端的时候更灵活   JS 实例 注释 控件 F.ready F.ready(function(){}); 就是ready 很多方法 ...

  7. FineUI开源版(ASP.Net)开发实践-目录

    点我订阅 目前所有博客的截图,方便离线观看,点图片 FineUI初学手册 下载,实例项目搭建 FineUI初学手册-部分JS整理 部分JS整理 ASP.NET-FineUI开发实践-1 实际开发环境是 ...

  8. ASP.NET MVC 4.0中选择Windows 验证默认出错拒绝访问的原因和解决方案

    在VS 2012或者2013 中,根据模板创建一个ASP.NET MVC 4.0的应用程序,选择下面的模板 然后选择Intranet Application 不对源代码做任何修改,直接按下F5调试,会 ...

  9. TP6.0中的密码验证逻辑、验证器的使用

    目录 1. 场景一:只有一个密码框,并且是可选项,留空不修改密码,不留空则修改密码 2. 场景二:两个密码框,修改密码时有新密码.确认密码,新密码框不为空时,确认密码才验证 1. 场景一:只有一个密码 ...

随机推荐

  1. HTML 基础篇

    本章内容: 简介 HTML定义 标签定义和属性 HTML5基本结构 HTML5字符集 <head>标签 <title> <base/> <link/>( ...

  2. DOM 事件深入浅出(一)

    在项目开发时,我们时常需要考虑用户在使用产品时产生的各种各样的交互事件,比如鼠标点击事件.敲击键盘事件等.这样的事件行为都是前端DOM事件的组成部分,不同的DOM事件会有不同的触发条件和触发效果.本文 ...

  3. 学习Redis你必须了解的数据结构——双向链表(JavaScript实现)

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/ 下午分享了JavaScript实现单向链表,晚上就来补充下双向链表吧.对链表 ...

  4. C# - 多线程 之 信号系统

    基础概览 多线程之信号系统命名空间 using System.Threading; 线程同步类的继承层次关系图 终止状态和非终止状态 在终止状态下,被WaitOne()阻塞的线程会逐个得到释放.如果一 ...

  5. 珍珠(bead)

    题目描述 有n颗形状和大小都一致的珍珠,它们的重量都不相同.n为整数,所有的珍珠从1到n编号.你的任务是发现哪颗珍珠的重量刚好处于正中间,即在所有珍珠的重量中,该珍珠的重量列(n+1)/2位.下面给出 ...

  6. spring源码:IOC(li)

    一.BeanDefinition BeanDefinition是配置文件<bean>元素标签在容器中内部表示形式.创建最终的BeanDefinition主要包括两个步骤: 1)利用Bean ...

  7. gRPC源码分析2-Server的建立

    gRPC中,Server.Client共享的Class不是很多,所以我们可以单独的分别讲解Server和Client的源码. 通过第一篇,我们知道对于gRPC来说,建立Server是非常简单的,还记得 ...

  8. jquery弹出可关闭遮罩提示框

    jquery CSS3遮罩弹出层动画效果,使用非常简单,就两个标签,里面自定义内容和样式,四种常见效果,懂的朋友还可以修改源代码修改成自己想要的效果 效果展示 http://hovertree.com ...

  9. iOS 性能调试

    性能调优的方式: 1.通过专门的性能调优工具 2.通过代码优化 1. 性能调优工具: 下面针对iOS的性能调优工具进行一个介绍: 1.1 静态分析工具–Analyze 相信iOS开发者在App进行Bu ...

  10. 如何理解javaScript对象?

    在我们生活中,常常会提到对象一词,如:你找到对象了吗?你的对象是谁呀?等等. 在我们家庭中,有男友的女青年都会说我有对象了,那么她的对象是XX(她的男友). 夫妻间呢?都会说我的爱人是谁谁谁,现在我们 ...