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 年間,我們看過太多的開源項目轟轟烈烈的來,平平淡淡的去,那些曾經熟悉的身影,曾經陪伴我們的代碼,都已經不復存在。其實很多時候,開源項目不是被新技術淘汰,而是被開源作者所丟棄,不免讓人扼腕嘆息。
每個存在都有存在的價值,時間總會讓之前的東西看起來不再那么新奇好玩,但是還有那么一幫曾經關注的網友,一直在使用的用戶,只有不斷的更新,才不會讓關心你的人失望。
?
?
任何事物的存在價值是無限的!
?
總結
以上是生活随笔為你收集整理的FineUI(开源版)v6.0中FState服务器端验证的实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android中webview load
- 下一篇: pt-online-schema-cha