今天來談談cookies欺騙是怎么回事以及如何避免。
用戶在登錄之后通常會保存用戶信息,以便在其他需要權限的頁面去驗證用戶信息是否具有訪問權限。
有同學說我在登錄的時候已經很注意SQL注入問題了,還有什么不安全的地方么?
當然有!這個要首先談一個問題,那就是用戶身份驗證的流程 如下圖:
因此我們可以看出,一個頁面是否能夠被訪問,判斷依據是通過存儲信息區域中用戶的信息來判斷的
而登錄頁面的作用就是 驗證 用戶輸入的用戶名+密碼的組合是否在數據庫中存在,如果存在則把信息保存在存儲信息的區域,以便各個頁面去判斷權限
OK,理清這個思路之后我們的重點就來了,那個信息存儲區域對于我們來說至關重要,一般常見的有兩種形式,session和cookies
session和cookies同樣都是針對單獨用戶的變量(或者說是對象好像更合適點),不同的用戶在訪問網站的時候 都會擁有各自的session或者cookies,不同用戶之間互不干擾。
他們的不同點是:
1,存儲位置不同
session在服務器端產生,比較安全,但是如果session較多則會影響性能
cookies在客戶端產生,安全性稍弱
2,生命周期不同
session生命周期 在指定的時間(如20分鐘)到了之后會結束,不到指定的時間,也會隨著瀏覽器進程的結束而結束。
cookies默認情況下也隨著瀏覽器進程結束而結束,但如果手動指定時間,則不受瀏覽器進程結束的影響。
由于如果用戶信息使用session保存的話,用戶信息往往會丟失而需要重新登錄,使用cookies的話則可以長時間有效比較利于用戶體驗,那session的情況我們不討論,下面說說使用cookies保存用戶信息的情況。
我們首先創建兩個頁面分別是Login.aspx和Main.aspx。Login.aspx用于獲取并保存用戶信息到cookies中,Main.aspx則用戶驗證用戶是否有權訪問本頁面,我們在本例中設定,登錄用戶有權訪問,匿名(未登錄)用戶,拒絕訪問。
首先來看Login.aspx 我們先創建兩個按鈕
“獲取登錄狀態”按鈕會 把信息保存到cookies中,這里僅保存UID,然后重定向到Main.aspx
“未獲取登錄狀態”按鈕 直接重定向到Main.aspx 進行匿名訪問
Login.aspx.cs 程序代碼:
1 PRotected void Page_Load(object sender, EventArgs e) 2 { 3 //每次加載登錄頁面 清理UID 清除登錄狀態 4 Response.Cookies["uid"].Value = "0"; 5 } 6 protected void Button1_Click(object sender, EventArgs e) 7 { 8 //驗證步驟略過,假設用戶通過驗證并且得到如下信息: 9 10 int uid = 1; //用戶唯一ID11 string username = "admin"; //用戶名12 string userpwd = "123456"; //用戶密碼13 14 //接下來要保存用戶登錄狀態15 Response.Cookies["uid"].Value = uid.ToString();16 17 //跳轉到登錄后的頁面18 Response.Redirect("Main.aspx");19 20 }21 protected void Button2_Click(object sender, EventArgs e)22 {23 //未經驗證直接進入Main.aspx24 Response.Redirect("Main.aspx");25 }
在Main.aspx中進行驗證用戶是否已經登錄
1 protected void Page_Load(object sender, EventArgs e) 2 { 3 CheckLogin(); 4 } 5 6 7 private void CheckLogin() 8 { 9 if (Request.Cookies["uid"] != null && GetUserInfo(int.Parse(Request.Cookies["uid"].Value), "") != "")10 {11 Response.Write(GetUserInfo(int.Parse(Request.Cookies["uid"].Value), "username") + "已登錄");12 }13 else14 {15 Response.Write("您尚未登陸,<a href='login.aspx'>點此登錄</a>");16 }17 }18 19 20 /// <summary>21 /// 模擬一個獲取用戶信息的方法22 /// 然而實際操作中需要通過ID查詢數據庫來獲取用戶信息23 /// 這里為了方便演示就直接return固定的值了24 /// </summary>25 /// <param name="uid"></param>26 /// <param name="key"></param>27 /// <returns></returns>28 private string GetUserInfo(int uid, string key)29 {30 if (uid == 1) //這里只設置uid為1的用戶,其他的UID的用戶不存在31 {32 switch (key)33 {34 case "username": return "admin";35 case "passWord": return "123456";36 default: return "null";37 }38 }39 else40 {41 return "";42 }43 }
OK,我們來測試一下,點擊獲取登錄狀態,實際上相當于用admin,123456這個組合來登錄。
好的,登錄成功,我們再來測試下匿名登錄,點擊未獲取登錄狀態
事情好像比我們想象的要順利,目前來說我們想要的效果已經都實現了,但是事實上真的是這樣嗎,顯然不是!
我們剛才說過,cookies是在客戶端產生,也就是我們自己的電腦上保存的
另一方面,Main.aspx這個頁面判斷 你是否能夠訪問的依據就是 cookies中的值是多少,如果是1,則認為你當前身份是UID為1的用戶,如果是5,則認為你當前身份是UID為5的用戶。
那么我們考慮一個事情,如果把我的cookies中的UID修改掉,比如改成35,是不是可以直接繞過登錄頁面,就可以以UID為35的用戶身份登錄呢?
事實上確實是這樣,這也就是標題中所說的cookies欺騙。由于cookies是客戶端產生我們可以很容易的修改,因此產生安全隱患。
下面就來實際測試一下,首先下載一款軟件 老兵cookies欺騙工具 界面如下圖:
在Address中輸入我們項目的訪問地址,然后連接
然后正常操作一遍,分別點擊 獲取登錄狀態 和 未獲取登錄狀態
發現我們正常操作是正常的判斷,下面重點來了,我們要修改cookies值 點擊未獲取登錄狀態 一樣可以被授權訪問
登錄成功了,那么我們應該如何避免這樣的問題呢?
正確的做法是,把密碼同時存入cookies(當然實際操作時候需要md5加密保存,這里為了方面演示使用明文保存),然后在Main.aspx驗證時候,同時驗證UID和密碼是否匹配即可。
我們來修改一下代碼:
Login頁面
1 protected void Page_Load(object sender, EventArgs e) 2 { 3 //每次加載登錄頁面 清理UID 清除登錄狀態 4 Response.Cookies["uid"].Value = "0"; 5 Response.Cookies["pwd"].Value = ""; 6 } 7 protected void Button1_Click(object sender, EventArgs e) 8 { 9 //驗證步驟略過,假設用戶通過驗證并且得到如下信息:10 11 int uid = 1; //用戶唯一ID12 string username = "admin"; //用戶名13 string userpwd = "123456"; //用戶密碼14 15 //接下來要保存用戶登錄狀態16 Response.Cookies["uid"].Value = uid.ToString();17 Response.Cookies["pwd"].Value = userpwd;18 //跳轉到登錄后的頁面19 Response.Redirect("Main.aspx");20 21 }22 protected void Button2_Click(object sender, EventArgs e)23 {24 //未經驗證直接進入Main.aspx25 Response.Redirect("Main.aspx");26 }
Main頁面
1 private void CheckLogin() 2 { 3 if (Request.Cookies["uid"] != null && Request.Cookies["pwd"] != null && GetUserInfo(int.Parse(Request.Cookies["uid"].Value), "") != "") 4 { 5 if (Request.Cookies["pwd"].Value == GetUserInfo(int.Parse(Request.Cookies["uid"].Value), "password")) 6 { 7 Response.Write(GetUserInfo(int.Parse(Request.Cookies["uid"].Value), "username") + "已登錄"); 8 } 9 else10 {11 Response.Write("您尚未登陸,<a href='login.aspx'>點此登錄</a>");12 }13 }14 else15 {16 Response.Write("您尚未登陸,<a href='login.aspx'>點此登錄</a>");17 }18 }
這樣改動之后,用戶如果再以修改cookies企圖繞過驗證的話,那么他除了修改UID之外,還必須修改pwd為正確的密碼。
有同學問:那如果他就是把PWD改成正確的密碼了呢?
這位同學...你的密碼都別別人竊取了...那么再安全的程序代碼也救不了你....
本文中案例源碼及相關工具下載:http://files.VEVb.com/webconfig/Cookies%E6%AC%BA%E9%AA%97.rar
感謝小伙伴們的熱烈討論,按照 @老牛吃肉 和其他同類觀點的用戶的建議,我嘗試做了另一方案,做下補充。
使用DES把UID加密放在cookies中,在驗證階段解密驗證。
http://www.49028c.com/webconfig/p/3624831.html
本文出自 低調碼農的筆記簿 http://www.49028c.com/webconfig/p/3623343.html 轉載請注明出處,如有謬誤不當之處,歡迎指正拍磚,不勝感謝?。?/p>
新聞熱點
疑難解答