FineUI(开源版)v6.0中FState服务器端验证的实现原理

前言

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(0, 3) + md5HashStr.Substring(md5HashStr.Length - 3, 3);
}

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

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

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

时间: 2024-10-10 09:19:42

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

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

一.客户端验证: 即用javaScript来验证. 1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <%@ taglib prefix="s" uri="/struts-tags" %> 4 <!DOCTYPE html PUBLIC &qu

vue-cli3.0 中 关闭 eslint 验证

直接上解决方式  不多bb 在package.json 中删除  @vue/prettier  就好了 在npm run dev 一下 原文地址:https://www.cnblogs.com/chris-zy/p/11718116.html

FineUI(开源版)v4.1.5 和(专业版)v1.9.0 发布

FineUI(开源版) 基于 ExtJS 的开源 ASP.NET 控件库 FineUI的使命 创建 No JavaScript,No CSS,No UpdatePanel,No ViewState,No WebServices 的网站应用程序 支持的浏览器 IE 8.0+.Chrome.Firefox.Opera.Safari 授权协议 Apache License v2.0 注:ExtJS 库在 GPL v3 协议下发布(http://www.sencha.com/license) 相关链接

FineUI(开源版)v4.2.2发布(8年125个版本,官网示例突破300个)!

开源版是 FineUI 的基石,从 2008 年至今已经持续发布了 120 多个版本,拥有会员 15,000 多位,捐赠会员达到 1,200 多位. FineUI(开源版)v4.2.2 是 8 年来的第 125 个版本,对表单.表格进行底层结构的重要调整,使其更简单更易于扩展,同时官网示例数也突破 300 个! v4.2.2主要更新内容: 1. 单元格编辑底层传输数据优化(但是不影响上层函数:GetModifiedDict.GetNewAddedList.GetDeletedList) 新版将新

网站对话框开源脚本--ArtDialog V6.0

初识对话框脚本觉得artDialog还是挺不错的开源的js脚本,最新版本都是V6.0 ,相对之前版本,artDialog的语法也发生很大的变化,windows对应的JS版本如下 点击下载 语法也发生变化,查看语法文档 artDialog主页面地址: http://aui.github.io/artDialog/ 帮助文档地址: http://aui.github.io/artDialog/doc/index.html#option 弹出对话框的开源JS,值得学习

8步安装多多客小程序全插件化1.0开源版

多多客(doodooke)小程序开源版 多多客免费开源的小程序SaaS系统,koa.js + vue.js插件化最佳实践. 安装部署 开发环境安装1.手动下载zip代码或者使用命令下载git clone https://gitee.com/doodooke/doodoo.git2.进入代码根目录,然后执行命令安装依赖yarn install3.进入mysql数据库,创建doodoo数据库4.首先修改.env?.env.web数据库配置文件,其他配置项可稍后配置5.执行命令启动npm run de

Rancher2.0中使用外置NFS存储部署Nginx实验

目录: 1.环境准备工作 1.1 准备好Rancher2.0集群环境 1.2 准备好外部NFS服务器 2.Rancher2.0中使用NFS存储的方法 2.1 在集群中创建持久卷(PV) 2.2 在项目/命名空间中创建数据卷(PVC) 2.3 部署工作负载(Nginx)时使用PVC 3.验证 3.1 在NFS目录中创建网页文件 3.2 访问网页   简述: Rancher2.0是一款非常棒的.开源免费的.易学易用的.企业级K8S容器云管理平台.有别于之前的Rancher1.6版,Rancher2.

浓缩版:云计算运维KVM监控工具之Sensu开源版

零.Sensu说明 1.Sensu 是由 Sonian 公司开发的一种监控框架,主要用于拥有大规模节点的云计算平台的检查与监控.目前发行的版本有企业版和开源版两种,收费的企业版本较之免费的开源版本拥有更多的功能.出于介绍的目的,本文的内容都是基于开源版本的 Sensu. 开源版本的 Sensu 遵循 MIT 许可,旨在为分布式的平台提供灵活易用.快速简单.便于拓展的监控和维护服务.主要包含以下功能与特性: 检查系统.服务和程序的运行状态. 基于分布式的设计,能够轻松的动态伸缩规模. 支持通过插件

开源搜索引擎Iveely 0.7.0发布,不一样,那就让他不一样!

2012年08月05日,Iveely Search Engine 0.1.0发布,今天,怀着对于未来的追求,终于,0.7.0如期和大家见面了,7个版本,历时2年4个月,感谢大家的支持,感谢我不离不弃的战友魏琪,奋斗到深夜,放弃了周末的社交,就为0.7.0如期而至:感谢Bogdan P Sliwowski先生,您的支持,让我们的激情和梦想靠得越来越近.下载安装编译部署,请参考Github,Web访问的时候,请确定您的浏览器支持WebSocket. 概  要 此次的版本,最大的技术改变是将纯C#迁移