FineUI(开源版)v6.0中FState服务器端验证的实现原理
前言
1. FineUI(開(kāi)源版)是完整開(kāi)源,最早發(fā)起于 2008-04,下載全部源代碼:http://fineui.codeplex.com/
2. 你可以通過(guò)捐贈(zèng)作者來(lái)支持FineUI(開(kāi)源版)的發(fā)展:http://fineui.com/donate/
?
FineUI的FState與ViewState
早在2013-01 我曾寫過(guò)一篇文章,對(duì)FState有詳細(xì)介紹:http://www.cnblogs.com/sanshi/archive/2013/01/08/2850459.html
現(xiàn)在來(lái)簡(jiǎn)要回顧一下:
1. ViewState是ASP.NET WebForm的基石,用來(lái)在頁(yè)面回發(fā)過(guò)程中維持控件狀態(tài),這樣我們才能在后臺(tái)方便的使用控件的服務(wù)器端屬性。
2. FineUI的AJAX回發(fā)過(guò)程中,相同的數(shù)據(jù)會(huì)同時(shí)存在于ViewState和返回的JavaScript代碼中,造成數(shù)據(jù)重復(fù)浪費(fèi)!
3. FState機(jī)制替換ViewState后,只會(huì)在回發(fā)數(shù)據(jù)中保留一份數(shù)據(jù),減少了數(shù)據(jù)的傳輸量。
?
對(duì)于,常見(jiàn)的誤解與糾正:
1. FineUI中不能使用ViewState了。錯(cuò)!!
???? FineUI只是實(shí)現(xiàn)了一套類似ViewState的機(jī)制,但是ViewState本身還是存在的,你依然可以在頁(yè)面上調(diào)用ViewState對(duì)象存儲(chǔ)數(shù)據(jù)。
2. 不使用ViewState了,FineUI控件不能維持狀態(tài)了。錯(cuò)!!
???? FState是在AJAX環(huán)境中對(duì)ViewState的一種改進(jìn)和提高,目的是為了減少數(shù)據(jù)傳輸量。你依然可以方便在C#代碼中使用控件屬性
?
FineUI中的FState可以被惡意篡改
FState用來(lái)在頁(yè)面回發(fā)過(guò)程中維持控件的狀態(tài),但是由于FState完全以JavaScript變量的形式暴露出來(lái),很容易被惡意用戶在客戶端進(jìn)行篡改。
首先來(lái)看一個(gè)簡(jiǎn)單的頁(yè)面:
<f:PageManager ID="PageManager1" runat="server" /> <f:DropDownList runat="server" ID="DropDownList1"><f:ListItem Text="可選項(xiàng)1" Value="Value1" Selected="true" /><f:ListItem Text="可選項(xiàng)2" Value="Value2" /><f:ListItem Text="可選項(xiàng)3" Value="Value3" /> </f:DropDownList> <f:Button runat="server" Text="提交" ID="btnSubmit" OnClick="btnSubmit_Click"></f:Button>后臺(tái)的按鈕事件:
protected void btnSubmit_Click(object sender, EventArgs e) {Alert.Show("下拉列表選中項(xiàng):" + DropDownList1.SelectedValue); }頁(yè)面運(yùn)行效果:
在頁(yè)面生成的HTML代碼,我們可以看到 f_state 的身影:
?
下面我們通過(guò)一個(gè)例子來(lái)講解 FState 的作用,假如用戶在前臺(tái)對(duì)下拉列表的數(shù)據(jù)進(jìn)行了重新綁定:
var ddl = F("DropDownList1"); var newdata = [["Data1", "數(shù)據(jù)1", 1],["Data2", "數(shù)據(jù)2", 1],["Data3", "數(shù)據(jù)3", 1] ]; ddl.store.loadData(newdata); ddl.setValue("Data1");此時(shí)點(diǎn)擊提交按鈕,效果:
之所以后臺(tái)取不到下拉列表的選中值,是因?yàn)楹笈_(tái)從FState恢復(fù)了下拉列表的項(xiàng)分別是“選項(xiàng)一”,“選項(xiàng)二”和“選項(xiàng)三”。
而對(duì)于客戶端重新綁定的新數(shù)據(jù)源,后臺(tái)一無(wú)所知,因此拿新的選中項(xiàng)值 Data1 去檢索時(shí),自然就找不到對(duì)應(yīng)的項(xiàng)了,所以此時(shí)SelectedValue==null
?
這個(gè)邏輯自然是正確的,但是由于 FState 是以JavaScript的形式返回到頁(yè)面的,所以惡意用戶自然就可以篡改這個(gè)值了:
var ddl = F("DropDownList1"); var newdata = [["Data1", "數(shù)據(jù)1", 1],["Data2", "數(shù)據(jù)2", 1],["Data3", "數(shù)據(jù)3", 1] ];ddl.f_state.F_Items = newdata; ddl.store.loadData(newdata); ddl.setValue("Data1");此時(shí)再點(diǎn)擊提交按鈕:
此時(shí)服務(wù)器已經(jīng)接受了這個(gè)客戶端惡意篡改的值!!這個(gè)就不對(duì)了。
?
如果是文本輸入框的值,我們自然是要手工進(jìn)行服務(wù)器端驗(yàn)證的,不要相信客戶端傳入的任何值,因?yàn)槎加锌赡鼙淮鄹?#xff01;
但是如果能默認(rèn)提供一種內(nèi)置的驗(yàn)證機(jī)制,讓這種惡意修改FState的行為消失,豈不是更好。FineUI v6.0對(duì)此進(jìn)行了增強(qiáng)。
?
FineUI v6.0 中默認(rèn)的FState服務(wù)器端驗(yàn)證
完全相同的例子,在 FineUI v6.0 中,如果通過(guò)客戶端修改下拉列表的f_state和內(nèi)部數(shù)據(jù),此時(shí)提交按鈕:
?
這個(gè)就是我們的保護(hù)機(jī)制,保護(hù)服務(wù)器端輸出的FState信息不會(huì)在客戶端被惡意修改。
那么這種保護(hù)機(jī)制是如何實(shí)現(xiàn)的呢?我們從生成的網(wǎng)頁(yè)代碼來(lái)分析一下:
?
可以看到,控件除了生成 f_state 屬性,還額外附加了一個(gè) f_state_v 屬性,這個(gè)很容易理解為對(duì) f_state 的加密值。
那么在頁(yè)面回發(fā)時(shí),只需要把這個(gè) f_state_v 的值一塊回發(fā),后臺(tái)進(jìn)行解密驗(yàn)證即可。我們來(lái)看下HTTP請(qǐng)求的參數(shù):
這里沒(méi)有 f_state_v 的身影,那是因?yàn)樗[藏在 F_STATE 變量中的,這個(gè)值是 Base64 編碼的,我們解碼后看下:
{"DropDownList1": [{"F_Items": [["Data1", "\u6570\u636e1", 1],["Data2", "\u6570\u636e2", 1],["Data3", "\u6570\u636e3", 1]],"SelectedValue": "Value1","SelectedValueArray": ["Value1"]}, "e1ae24"] }可以看到,這個(gè) f_state_v 的確一起回發(fā)到后臺(tái)了。
這個(gè)邏輯其實(shí)并不復(fù)雜:
1. 頁(yè)面初始化時(shí),除了生成控件的 f_state 之外,還額外的生成一個(gè)加密后的信息 f_state_v
2. 頁(yè)面回發(fā)時(shí),后臺(tái)把這兩個(gè)值進(jìn)行校驗(yàn),就知道是否在客戶端被修改了
3. 如果后臺(tái)控件的屬性發(fā)生變化,還重新生成 f_state_v 更新到前臺(tái)
?
這里給出后臺(tái)的主要邏輯代碼,完整源代碼請(qǐng)自行下載:
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; }?
小結(jié)
這篇文章講解了FineUI中的FState取代ViewState的原因,惡意用戶如何在客戶端篡改FState,然后介紹了FineUI v6.0對(duì) FState 的保護(hù)機(jī)制。
然后我們從生成的頁(yè)面HTML入手,簡(jiǎn)要分析了FState驗(yàn)證機(jī)制的實(shí)現(xiàn)原理。
?
感興趣的朋友可以自行下載源代碼分析:http://fineui.codeplex.com/
?
關(guān)于開(kāi)源和堅(jiān)持
FineUI(開(kāi)源版)開(kāi)始于 2008-04,8年多時(shí)間內(nèi),我們堅(jiān)持更新了 128 個(gè)版本,內(nèi)部使用的 extjs 從最初的 v2.x,v3.x,到后來(lái)的v4.x,FineUI v6.0 使用了最新的extjs v6.2.0。
8 年間,我們看過(guò)太多的開(kāi)源項(xiàng)目轟轟烈烈的來(lái),平平淡淡的去,那些曾經(jīng)熟悉的身影,曾經(jīng)陪伴我們的代碼,都已經(jīng)不復(fù)存在。其實(shí)很多時(shí)候,開(kāi)源項(xiàng)目不是被新技術(shù)淘汰,而是被開(kāi)源作者所丟棄,不免讓人扼腕嘆息。
每個(gè)存在都有存在的價(jià)值,時(shí)間總會(huì)讓之前的東西看起來(lái)不再那么新奇好玩,但是還有那么一幫曾經(jīng)關(guān)注的網(wǎng)友,一直在使用的用戶,只有不斷的更新,才不會(huì)讓關(guān)心你的人失望。
?
?
任何事物的存在價(jià)值是無(wú)限的!
?
總結(jié)
以上是生活随笔為你收集整理的FineUI(开源版)v6.0中FState服务器端验证的实现原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android中webview load
- 下一篇: pt-online-schema-cha