ASP.NET中Cookie編程的基礎(chǔ)知識(6)
發(fā)表時(shí)間:2024-06-10 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]刪除 Cookie 刪除 Cookie(即把該 Cookie 從用戶的硬盤上物理刪除)是修改 Cookie 的一種形式。由于 Cookie 位于用戶的計(jì)算機(jī)中,所以您無法直接將其刪除。但是,您可以讓瀏覽器為您刪除 Cookie。修改 Cookie 的方法前面已經(jīng)介紹過(即用相同的名稱創(chuàng)建一個(gè)新的...
刪除 Cookie
刪除 Cookie(即把該 Cookie 從用戶的硬盤上物理刪除)是修改 Cookie 的一種形式。由于 Cookie 位于用戶的計(jì)算機(jī)中,所以您無法直接將其刪除。但是,您可以讓瀏覽器為您刪除 Cookie。修改 Cookie 的方法前面已經(jīng)介紹過(即用相同的名稱創(chuàng)建一個(gè)新的 Cookie),不同的是將其有效期設(shè)置為過去的某個(gè)日期。當(dāng)瀏覽器檢查 Cookie 的有效期時(shí),就會刪除這個(gè)已過期的 Cookie。
所以,刪除 Cookie 的方法與創(chuàng)建該 Cookie 的方法是相同的,只不過要把其有效期設(shè)置為過去的某個(gè)日期。以下示例比刪除單個(gè) Cookie 要稍微有趣一些,它使用的方法可以刪除當(dāng)前域的所有 Cookie:
Dim i As Integer
Dim cookieName As String
Dim limit As Integer = Request.Cookies.Count - 1
For i = 0 To limit
aCookie = Request.Cookies(i)
aCookie.Expires = DateTime.Now.AddDays(-1)
Response.Cookies.Add(aCookie)
Next
修改或刪除子鍵
修改單個(gè)子鍵的方法與最初創(chuàng)建它的方法相同:
Response.Cookies("userInfo")("lastVisit") = DateTime.Now.ToString
Response.Cookies("userInfo").Expires = DateTime.Now.AddDays(1)
比較復(fù)雜的問題是如何刪除單個(gè)子鍵。您不能只是簡單地重新設(shè)置 Cookie 的過期日期,因?yàn)檫@樣只能刪除整個(gè) Cookie 而不能刪除單個(gè)子鍵。實(shí)際的解決方案是對包含子鍵的 Cookie 的 Values 集合進(jìn)行操作。首先,通過從 Request.Cookies 對象中獲取 Cookie 來重新創(chuàng)建 Cookie。然后,您就可以調(diào)用 Values 集合的 Remove 方法,將要?jiǎng)h除的子鍵名稱傳遞到 Remove 方法。接下來,您通?梢詫⑿薷暮蟮 Cookie 添加到 Response.Cookies 集合,以便將修改后的 Cookie 發(fā)送回瀏覽器。
以下代碼顯示了如何刪除子鍵。在示例中,要?jiǎng)h除的子鍵的名稱在變量中指定。
Dim subkeyName As String
subkeyName = "userName"
Dim aCookie As HttpCookie = Request.Cookies("userInfo")
aCookie.Values.Remove(subkeyName)
aCookie.Expires = DateTime.Now.AddDays(1)
Response.Cookies.Add(aCookie)
Cookie 與安全性
在使用 Cookie 時(shí),您必須意識到其固有的安全弱點(diǎn)。我所指的安全性并不是隱私問題,正如我在前面的什么是 Cookie?中所述,隱私在更大程度上是某些用戶面對的問題:這些用戶很關(guān)心 Cookie 中的信息是如何被使用的。而 Cookie 的安全性問題與從客戶機(jī)獲取數(shù)據(jù)的安全性問題類似。對于初學(xué)者,就應(yīng)用程序而言,Cookie 是用戶輸入的另一種形式,因而很容易被他人非法獲取和利用。由于 Cookie 保存在用戶自己的計(jì)算機(jī)上,所以用戶至少可以看到您保存在 Cookie 中的信息。如果用戶愿意,還能在瀏覽器向您發(fā)送 Cookie 之前修改該 Cookie。
所以,您千萬不要在 Cookie 中保存保密信息 - 用戶名、密碼、信用卡號等等。在 Cookie 中不要保存不應(yīng)該由用戶掌握的內(nèi)容,也不要保存可能被其他竊取 Cookie 的人控制的內(nèi)容。
同樣,要對從 Cookie 中得到的任何信息都持懷疑態(tài)度。不要認(rèn)為得到的數(shù)據(jù)就是您當(dāng)初設(shè)想的信息。處理 Cookie 值時(shí)采用的安全措施應(yīng)該與處理 Web 頁面中用戶鍵入的數(shù)據(jù)時(shí)采用的安全措施相同。例如,在頁面中顯示值之前,我會對 Cookie 中的內(nèi)容進(jìn)行 HTML 編碼。這是一種標(biāo)準(zhǔn)的方法,可以在顯示之前凈化從用戶處得到的信息,對 Cookie 的處理與此相同。
另一個(gè)需要關(guān)心的問題是,Cookie 是以純文本的形式在瀏覽器和服務(wù)器之間傳送的,任何可以截取 Web 通信的人都可以讀取 Cookie。您可以對 Cookie 的屬性進(jìn)行設(shè)置,使其只能在使用安全套接字層(SSL,又稱 https://)的連接上傳輸。SSL 并不能防止保存在用戶計(jì)算機(jī)上的 Cookie 被他人讀取或操作,但它能防止 Cookie 在傳輸途中被他人截取。本文不討論 SSL,但您必須清楚,您可以對 Cookie 進(jìn)行傳輸保護(hù)。有關(guān) SSL 的詳細(xì)信息,請參閱 Secure Sockets Layer: Protect Your E-Commerce Web Site with SSL and Digital Certificates(英文)。
面對這些安全問題,如何才能安全地使用 Cookie?您可以在 Cookie 中保存一些不重要的數(shù)據(jù),如用戶首選項(xiàng)或其他對應(yīng)用程序沒有重大影響的信息。如果確實(shí)需要把某些敏感信息(如用戶 ID)保存在 Cookie 中,就對這些信息進(jìn)行加密。一種可行的方法是利用 ASP.NET Forms Authentication 實(shí)用程序創(chuàng)建一個(gè)身份驗(yàn)證票據(jù),作為 Cookie 保存。本文不討論有關(guān)加密的問題,但是,如果您需要在 Cookie 中保存敏感信息,就應(yīng)該試著采取措施來隱藏信息,防止被他人盜用。
在 Mitigating Cross-site Scripting With HTTP-only Cookies(英文)一文中,您可以了解到更多有關(guān) Cookie 及其安全弱點(diǎn)的信息。
檢查瀏覽器是否接受 Cookie
我在前面的 Cookie 的限制一節(jié)中曾經(jīng)提到一個(gè)潛在問題,即用戶可以設(shè)置自己的瀏覽器拒絕接受 Cookie。如何才能知道您是否可以讀寫 Cookie?在不能寫入 Cookie 時(shí)不會出現(xiàn)任何錯(cuò)誤(例如 Response.Cookies 不會拋出異常),因?yàn)榉⻊?wù)器并不跟蹤呈現(xiàn)頁面后出現(xiàn)的情況。瀏覽器同樣不會向服務(wù)器發(fā)送任何有關(guān)其當(dāng)前的 Cookie 設(shè)置的信息。(也許您需要了解,但 HttpBrowserCapabilities.Cookies Property [英文] 屬性并不會告訴您 Cookie 是否被啟用,而只能告訴您當(dāng)前的瀏覽器是否支持 Cookie。)
一種確定瀏覽器是否接受 Cookie 的方法是先編寫一個(gè) Cookie,然后再嘗試讀取這個(gè) Cookie。如果不能讀取這個(gè) Cookie,則可以認(rèn)為該瀏覽器不接受 Cookie。
我編寫了一個(gè)簡單的示例來說明如何測試 Cookie 是否被接受。該示例包含兩個(gè)頁面。在第一個(gè)頁面中,我編寫了一個(gè) Cookie,然后把瀏覽器重新定向到第二個(gè)頁面。第二個(gè)頁面嘗試讀取這個(gè) Cookie,轉(zhuǎn)而將瀏覽器重新定向到第一個(gè)頁面,并向 URL 添加一個(gè)帶有測試結(jié)果的查詢字符串變量。
第一個(gè)頁面的代碼如下:
Sub Page_Load()
If Not Page.IsPostBack Then
If Request.QueryString("AcceptsCookies") Is Nothing Then
Response.Cookies("TestCookie").Value = "ok"
Response.Cookies("TestCookie").Expires = _
DateTime.Now.AddMinutes(1)
Response.Redirect("TestForCookies.aspx?redirect=" & _
Server.UrlEncode(Request.Url.ToString))
Else
labelAcceptsCookies.Text = "接受 Cookie = " & _
Request.QueryString("AcceptsCookies")
End If
End If
End Sub
第一個(gè)頁面測試是否有回信,如果沒有,就搜索包含測試結(jié)果的查詢字符串變量 (AcceptsCookies)。如果沒有找到查詢字符串變量,則表示測試還沒有完成,代碼就寫出一個(gè)名為“TestCookie”的 Cookie。寫出 Cookie 之后,示例調(diào)用 Response.Redirect 來切換到測試頁面 (TestForCookies.aspx)。附加到測試頁面的 URL 的是名為 redirect 的查詢字符串變量,該變量中包含了當(dāng)前頁面的 URL,這樣就能在執(zhí)行測試后把重定向到該頁面。
測試頁面可以完全由代碼組成,不需要包含控件。以下就是我使用的代碼:
Sub Page_Load()
Dim redirect As String = Request.QueryString("redirect")
Dim acceptsCookies As String
' 是否接受 Cookie?
If Request.Cookies("TestCookie") Is Nothing Then
' 沒有 Cookie,因此不需要接受
acceptsCookies = 0
Else
acceptsCookies = 1
' 刪除測試 Cookie
Response.Cookies("TestCookie").Expires = _
DateTime.Now.AddDays(-1)
End If
Response.Redirect(redirect & "?AcceptsCookies=" & acceptsCookies, _
True)
End Sub
讀取 redirect 查詢字符串變量后,代碼就嘗試讀取 Cookie。為了實(shí)現(xiàn)日常管理,如果該 Cookie 確實(shí)存在,就會被立即刪除。測試完成后,代碼從 redirect 查詢字符串變量傳遞的 URL 構(gòu)造一個(gè)新的 URL。新的 URL 也包括一個(gè)包含測試結(jié)果的查詢字符串變量。最后一步是使用新的 URL 將瀏覽器重定向到原來的頁面。
這個(gè)示例十分簡單,但說明了通過運(yùn)行程序并查看結(jié)果來進(jìn)行測試的基本原則。其中最需要改進(jìn)的地方是要永久保存 Cookie 測試結(jié)果,這樣用戶就不必在每次瀏覽原始頁面時(shí)都重復(fù)進(jìn)行測試。但是,實(shí)際上并不能做到這一點(diǎn)。Cookie 不會起作用,原因是顯而易見的。另一種可能是把測試結(jié)果保存在會話狀態(tài)中,但在默認(rèn)情況下,會話狀態(tài)也依賴于 Cookie,而如果瀏覽器不接受 Cookie,會話狀態(tài)也不會起作用。解決后一個(gè)問題的辦法是采用無 Cookie 的會話狀態(tài)。下一節(jié)我將簡要介紹會話狀態(tài)如何與 Cookie 協(xié)作。
Cookie 和會話狀態(tài)
當(dāng)用戶訪問您的站點(diǎn)時(shí),服務(wù)器會為該用戶創(chuàng)建唯一的會話,會話將一直延續(xù)到用戶訪問結(jié)束。對于每個(gè)會話,ASP.NET 都維護(hù)一種基于服務(wù)器的結(jié)構(gòu)(會話狀態(tài)),在該結(jié)構(gòu)中應(yīng)用程序可以保存用戶的相關(guān)信息。有關(guān)詳細(xì)信息,請參閱 Session State(英文)。
ASP.NET 需要能跟蹤每個(gè)用戶的會話 ID,這樣才能把用戶映射到服務(wù)器上的會話狀態(tài)信息。默認(rèn)情況下,ASP.NET 使用一個(gè)非永久性的 Cookie 來保存會話狀態(tài)。如果您使用讀取 Cookie 一節(jié)的“讀取 Cookie 集合”中的示例,您可能就會在 Cookie 中發(fā)現(xiàn)一個(gè)會話狀態(tài) Cookie。
但是如果用戶禁用了瀏覽器的 Cookie,會話狀態(tài)就不能使用 Cookie 來保存會話 ID,會話狀態(tài)也不會起作用。這就是為什么我在前面的檢查瀏覽器是否接受 Cookie 中說,無法在 Cookie 測試完畢后把測試結(jié)果實(shí)際保存在會話狀態(tài)中,因?yàn)闆]有 Cookie 就沒有會話狀態(tài)。
ASP.NET 提供了一種解決方案,即利用無 Cookie 的會話。您可以配置自己的應(yīng)用程序,不在 Cookie 中保存會話 ID,而是在站點(diǎn)頁面的 URL 中保存。會話 ID 保存在 URL 中,也就是 ASP.NET 將 ID 保存在瀏覽器中,從而能夠在用戶請求其他頁面時(shí)取回 ID。
無 Cookie 會話可以避免瀏覽器拒絕 Cookie 的問題,使您能夠使用會話狀態(tài)。如果您的應(yīng)用程序依賴于會話狀態(tài),您可能就需要對其進(jìn)行配置,使它能使用無 Cookie 會話。但是,在某些情況下,如果用戶與其他人共享 URL - 可能是用戶通過電子郵件將 URL 發(fā)送給同事,而該用戶的會話仍然處于激活狀態(tài) - 那么最終這兩個(gè)用戶可能共享同一個(gè)會話,結(jié)果將難以預(yù)料。