不拖控制項ASP.NET—探知cookie和session(1),asp.netcookie
1. 為什麼會出現cookie和session? Ø 先看一個例子: 我們還是使用之前的NVelocity,不清楚的參看連結:http://blog.csdn.net/u010955843/article/details/42977533,同樣建立commonhelper類,裡面封裝NVelocity模板,並且建立html也作為渲染的模板進行顯示。 html頁
<span style="font-family:Microsoft YaHei;"><strong><strong><span style="font-family:Microsoft YaHei;font-size:14px;"><!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title></head><body> <form action="../zhuangtaibaochiHttpNoState.ashx" method="get"> <input type="submit" value="增加" /> <p>$Model.Count</p> </form></body></html></span></strong></strong></span>
一般處理常式
<span style="font-family:Microsoft YaHei;"><strong><strong><span style="font-family:Microsoft YaHei;font-size:14px;">using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace zhuangtaibaochi{ /// <summary> /// zhuangtaibaochiHttpNoState 的摘要說明 /// </summary> public class zhuangtaibaochiHttpNoState : IHttpHandler { private int i=1; public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/html"; context.Response.Write("Hello World"); i++; string html = commonHelper.RenderHtml("HttpNozhuangtai.html",new{ Count=i}); context.Response.Write(html); } public bool IsReusable { get { return false; } } }}</span></strong></strong></span>
commonhelper修改一處即可,其實可以不改,自己設計的填充模板的資料的名字,可以隨便設計
<span style="font-family:Microsoft YaHei;"><strong><strong><span style="font-family:Microsoft YaHei;font-size:14px;">using NVelocity;using NVelocity.App;using NVelocity.Runtime;using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace zhuangtaibaochi{ public class commonHelper { /// <summary> /// 用data資料填充templateName模板,渲染產生html返回 /// </summary> /// <param name="templateName">模板名字</param> /// <param name="data">填充模板資料</param> /// <returns></returns> public static string RenderHtml(string templateName, object data) { VelocityEngine vltEngine = new VelocityEngine(); vltEngine.SetProperty(RuntimeConstants.RESOURCE_LOADER, "file"); vltEngine.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, System.Web.Hosting.HostingEnvironment.MapPath("~/templates"));//模板檔案所在的檔案夾,我們遵從上次講的我們還是放在templates這個檔案夾中,自己也可以建立別的名字的 vltEngine.Init(); //引擎初始化 VelocityContext vltContext = new VelocityContext(); vltContext.Put("Model", data);//設定參數,在模板中可以通過$data來引用 Template vltTemplate = vltEngine.GetTemplate(templateName);//渲染的html模板 System.IO.StringWriter vltWriter = new System.IO.StringWriter(); vltTemplate.Merge(vltContext, vltWriter); string html = vltWriter.GetStringBuilder().ToString(); return html; } }}</span></strong></strong></span>
我們發現即使每次點擊增加按鈕,數字2都不會改變,原因在於http協議是無狀態的。可以自己試試。
Ø 再看一個例子:通過隱藏欄位讓http記住狀態
同上例,只是修改html頁和一般處理常式,commhelper不需要改變
html頁
<span style="font-family:Microsoft YaHei;"><strong><strong><span style="font-family:Microsoft YaHei;font-size:14px;"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title></head><body> <form action="HtttpNoZhuangTai.ashx" method="get"> <input type="submit" value="增加" /> <input type="hidden" name="Count" value="$Model.Count" /> <p>$Model.Count</p> </form></body></html></span></strong></strong></span>
一般處理常式,只是修改ProcessRequest方法
<span style="font-family:Microsoft YaHei;"><strong><strong><span style="font-family:Microsoft YaHei;font-size:14px;"> private int i=1; public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/html"; //context.Response.Write("Hello World"); //i++; //string html = commonHelper.RenderHtml("HttpNozhuangtai.html",new{ Count=i}); //context.Response.Write(html); //從病曆本讀出上次的值 int count = Convert.ToInt32(context.Request["Count"]); count++; //新的值寫入病曆本 string html = commonHelper.RenderHtml("HttpNozhuangtai.html", new { Count = count }); context.Response.Write(html); }</span></strong></strong></span>
此時當我們點擊的時候發現實現了每次數目的遞增,這是因為我們將值儲存在了隱藏欄位裡面,這樣需要的時候可以方便地調出來。比如我們可以把用戶端假定為病人,服務端看成是醫生,我們知道當醫生診斷完一個患者,會給病人一個病曆本,這樣下次來看的時候就會根據上次的診斷情況來確定這次如何去診斷,讓用戶端(病人)幫你儲存欄位,此時隱藏欄位相當於病曆本,隱藏欄位記住了之前的狀態,當需要的時候再次調出,這樣就實現了資料遞增。
但是我們因為是get提交,使用者是可以更改資訊,這樣就會出現資訊的不安全性,所以存放在用戶端的必須是使用者更改之後頁無所謂的,否則存在很大的問題。
Ø 無狀態http協議簡介
http協議是無狀態的,不會記得上次和網頁“發生了什麼”。伺服器不記的上次給了瀏覽器什麼,否則伺服器的壓力太大,瀏覽器需要記住這些值,下次再提交伺服器的時候,就要把上次的值交給伺服器,讓他想起來。如果要知道上一次的狀態,一個方法是在對瀏覽器響應結束之前將狀態資訊儲存到頁面表單總(實現一下),下次頁面再向伺服器發出請求的時候帶上這些狀態資訊,這樣伺服器就能根據這些狀態資訊還原上次的狀態了,類似於去看病的病曆本。
盡量不要這麼幹(將資訊儲存在服務端),用戶端的事情讓用戶端去做。
狀態資訊儲存在隱藏欄位中的缺點:加大網站的流量、降低訪問速度、機密資料放到表單中會有資料欺騙等安全性問題。
2. Cookie
隱藏欄位實現不了自由傳遞資料和讀取資料,只有需要時候發送請求,之後伺服器再響應。故而cookie應運而生。
Ø 什麼是cookie?
如果想要實現自由的傳遞和讀取,用cookie。Cookie是和網站相關的,並且每次向伺服器請求的時候除了發送表單參數外,還會將和網站相關的所有的cookie都提交給伺服器,是強制性的。Cookie也是儲存在瀏覽器端的,而且瀏覽器會在每次請求的時候都會把和這個網站相關的cookie提交到伺服器,並且將服務端返回的cookie更新回資料庫,因此可以將資訊儲存在cookie中,然後在伺服器端讀取和修改。伺服器返回資料除了普通的html資料以外,還會返回修改的cookie,瀏覽器把拿到的cookie值更新本地瀏覽器的cookie就可以。
此外存到瀏覽器中,也就是本地電腦中,是可讀可寫的,只有網站自己可以讀寫的,別人是讀不了的,避免了隱私外泄的安全隱患。也就是與網域名稱(網域名稱不同,網站不同)相關的,本地區名或者自己的網域名稱才能讀,誰寫誰讀;存到本地硬碟中,瀏覽器通過報文欄位發過去,每次向伺服器請求,都會發送cookie,瀏覽器在後台通過報文欄位進行發送。
Ø 樣本
建立一般處理常式名為cookieTest.ashx
<span style="font-family:Microsoft YaHei;"><strong><strong><span style="font-family:Microsoft YaHei;font-size:14px;">using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace zhuangtaibaochi{ /// <summary> /// cookieTest 的摘要說明 /// </summary> public class cookieTest : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/html"; //context.Response.Write("Hello World"); string read=context.Request["Read"]; if (!string.IsNullOrEmpty(read)) { HttpCookie cookie = context.Request.Cookies["Age"]; string value = cookie.Value; var data = new { Value = value }; string html = commonHelper.RenderHtml("cookieTest.html", data); context.Response.Write(html); } else if (!string.IsNullOrEmpty(context.Request["Write"])) { context.Response.SetCookie(new HttpCookie("Age", "33")); string html = commonHelper.RenderHtml("cookieTest.html", null); context.Response.Write(html); } else { string html = commonHelper.RenderHtml("cookieTest.html", null); context.Response.Write(html); } } public bool IsReusable { get { return false; } } }}</span></strong></strong></span>
html頁
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form action="../cookieTest.ashx" method="post">
<input type="submit" name="Read" value="讀" />
<input type="submit" name="Write" value="寫" />
讀出來的cookie:$Model.Value
</form>
</body>
</html>
commonhelper同上面的
這樣我們便可以讀取cookie的值。
Ø 報文分析
運行程式,並且開啟firebug(Firefox瀏覽器)其他瀏覽器中快速鍵F12或者工具菜單下面的開發人員工具均可以查看。
此時重新整理頁面可以看到我們發送的請求:
這時候我們可以點擊寫,因為此時沒有cookie我們需要存入一個cookie
此時設定課cookie,存在瀏覽器的某個地方;下次再發請求的時候直接讀取cookie即可,此時執行的是處理常式的讀方法,也就是可以在伺服器端通過request.cookie進行擷取了。此時點擊讀顯示
Cookie在用戶端是以鍵值對的形式存在的,告訴cookie進行儲存
點擊寫按鈕的時候執行寫進一個cookie,當點擊讀的時候將所儲存的cookie進行讀出來的操作,讀取的時候通過報文進行讀取,利用報文進行讀取的和傳遞的
Ø 限制
Cookie的缺點是不能儲存過多的資訊,機密資訊不能存;Cookie無法跨不同的瀏覽器,Cookie存在用戶端,故而存在安全性的問題,cookie是可以被清除的,不能把不能丟的資料存到cookie中;cookie尺寸有限制,一般為幾k或者幾百k。
如何清除Cookis,我們以ie為例
點擊工具—Internet選項
點擊刪除時顯示
Ø 到期問題
瀏覽器關閉之後那麼cookie就會到期不再存在(預設情況下),如何使得瀏覽器關閉之後仍可以存在呢?
設定到期日期是一天后的,也就是一天后的這個時間
在上述的例子上修改cookieTest.ashx中的部分代碼即可
<span style="font-family:Microsoft YaHei;"><strong><strong><span style="font-family:Microsoft YaHei;font-size:14px;">else if (!string.IsNullOrEmpty(context.Request["Write"])) { //SetCookie(new HttpCookie("Age", "33")) Cookie生命週期是瀏覽器的生命週期 //瀏覽器重啟就自動刪除了 //context.Response.SetCookie(new HttpCookie("Age", "33")); HttpCookie cookie1 = new HttpCookie("Age", "33"); cookie1.Expires = DateTime.Now.AddDays(1); context.Response.SetCookie(cookie1); context.Response.SetCookie(new HttpCookie("Name", "yzk")); string html = commonHelper.RenderHtml("cookieTest.html", null); context.Response.Write(html); } else { string html = commonHelper.RenderHtml("cookieTest.html", null); context.Response.Write(html); }</span></strong></strong></span>
此時點擊寫查看報文資訊,看到了伺服器端響應的被設定的cookie以及到期日期,到期之後的新的cookie
如果瀏覽器滿了就會根據優先順序或者最先存的刪除掉了,到期時間是最多,並不是肯定就是那個日期。
不設定cookie的失效時間,預設的就是關閉瀏覽器就會使得其失效,這樣都不安全,因為用戶端使用者可以修改cookie的值。Cookie相當於病曆本,寫到病曆本,使用者不會篡改cookie。也就是使用者不會篡改病曆本(把自己的病情寫成別的,但是不一定),也就是存在修改,是不安全的。同時使用者會擔心醫生修改病曆本,故而這樣寫到病曆本上的資訊就不安全。如何防止病人修改或者醫生修改或者家屬修改修改病曆本呢?
Cookie不能儲存機密資料,如果想儲存機密資料,可以儲存一個Guid(通用唯一識別碼(GUID,Globally Unique Identifier)也稱作 UUID(Universally Unique IDentifier) 。GUID是一種由演算法產生的二進位長度為128位的數位識別碼符。GUID主要用於在擁有多個節點、多台電腦的網路或系統中。在理想情況下,任何電腦和電腦叢集都不會產生兩個相同的GUID。GUID 的總數達到了2^128(3.4×10^38)個,所以隨機產生兩個相同GUID的可能性非常小,但並不為0。)到Cookie中,然後在伺服器端建建立一個以Guid為Key,複雜資料為Value全域Dictionary。
3. 總結
存到用戶端瀏覽器是很容易修改的,故而存在安全隱患,所以引出來了伺服器端的機制,那就沒有辦法修改了,故而伺服器端的資料安全性較用戶端好的多,並且在其他的頁面也能取到資料。
下篇部落格我們將繼續進行另一種較為安全的伺服器端的機制那就是session的講解,請繼續關注~