Cookie確實在WEB應用方面為訪問者和編程者都提供了方便,然而從安全方面考慮是有問題的,首先,Cookie資料包含在HTTP請求和響應的包頭裡透明地傳遞,也就是說聰明的人是能清清楚楚看到這些資料的
。其次,Cookie資料以Cookie檔案格式儲存在瀏覽者電腦的cache目錄裡,其中就包含有關網頁、密碼和其他使用者行為的資訊,那麼只要進入硬碟就能開啟Cookie檔案。圖1是一個Cookie檔案的內容: 如果你未曾留意你的機器裡有Cookie檔案,可以按下列方法查看:開啟IE,選擇“工具”菜單裡的“Internet選項”,然後在彈出的對話方塊裡點擊“設定”按鈕,在設定對話方塊裡點擊“查看”鈕,就會開啟一個視窗顯示瀏覽器放在硬碟裡的所有快取資料,其中就有大量的Cookie檔案。 所以奉勸大家不要將敏感的使用者資料存放在Cookie中,要麼就通過加密將這些資料保護起來。 在以前的ASP版本中沒有加密的功能,現在.NET構架在System.Security.Cryptography命名空間裡提供了許多加密類可以利用。 一、.NET的密碼系統概要 簡單地說,加密就是將原始字元(位元組)串轉變為完全不同的字串的處理過程,達到原始字元無法破譯的目的。這個處理過程是用另一個字串(稱為“密鑰”),採取複雜的、混合的演算法,“搗進”原始字串。有時還使用一個稱為“初始向量”的字串,在密鑰搗進之前先打亂目標字串,預防目標字串中較明顯的內容被識破。加密的功效取決於所用密鑰的大小,密鑰越長,保密性越強。典型的密鑰長度有64位、128位、192位、256位和512位。攻擊者唯一的方法是建立一個程式嘗試每一個可能的密鑰組合,但64位密鑰也有72,057,594,037,927,936種組合。 目前有兩種加密方法:對稱式加密(或稱私人密鑰)和非對稱式加密(或稱公用密鑰)。對稱式加密技術的資料交換兩邊(即加密方和解密方)必須使用一個保密的私人密鑰。非對稱式加密技術中,解密方向加密方要求一個公用密鑰,加密方在建立一個公用密鑰給解密方後,用公用密鑰建立唯一的私人密鑰。加密方用私人祕密金鑰加密送出的資訊,對方用公用密鑰解密。保護HTTP傳輸安全的SSL就是使用非對稱技術。 我們對Cookie資料的加密採取對稱式加密法。.NET構架從基本的SymmetricAlgorithm類擴充出來四種演算法: ·System.Security.Cryptography.DES ·System.Security.Cryptography.TripleDES ·System.Security.Cryptography.RC2 ·System.Security.Cryptography.Rijndael 下面將示範DES和TripleDES演算法。DES的密鑰大小限制在64位,但用於Cookie的加密是有效。TripleDES完成了三次加密,並有一個較大的密鑰位元,所以它更安全。使用那一種演算法不僅要考慮加密強度,還要考慮Cookie的大小。因為加密後的Cookie資料將變大,並且,密鑰越大,加密後的資料就越大,然而Cookie資料的大小限制在4KB,這是一個必須考慮的問題。再者,加密的資料越多或演算法越複雜,就會佔有更多的伺服器資源,進而減慢整個網站的訪問速度。 二、建立一個簡單的加密應用類 .NET的所有加密和解密通過CryptoStream類別來處理,它衍生自System.IO.Stream,將字串作為以資料流為基礎的模型,供加密轉換之用。下面是一個簡單的加密應用類的代碼: Imports System.Diagnostics Imports System.Security.Cryptography Imports System.Text Imports System.IO Public Class CryptoUtil '隨機選8個位元組既為密鑰也為初始向量 Private Shared KEY_64() As Byte = {42, 16, 93, 156, 78, 4, 218, 32} Private Shared IV_64() As Byte = {55, 103, 246, 79, 36, 99, 167, 3} '對TripleDES,採取24位元組或192位的密鑰和初始向量 Private Shared KEY_192() As Byte = {42, 16, 93, 156, 78, 4, 218, 32, _ 15, 167, 44, 80, 26, 250, 155, 112, _ 2, 94, 11, 204, 119, 35, 184, 197} Private Shared IV_192() As Byte = {55, 103, 246, 79, 36, 99, 167, 3, _ 42, 5, 62, 83, 184, 7, 209, 13, _ 145, 23, 200, 58, 173, 10, 121, 222} '標準的DES加密 Public Shared Function Encrypt(ByVal value As String) As String If value <> "" Then Dim cryptoProvider As DESCryptoServiceProvider = _ New DESCryptoServiceProvider() Dim ms As MemoryStream = New MemoryStream() Dim cs As CryptoStream = _ New CryptoStream(ms, cryptoProvider.CreateEncryptor(KEY_64, IV_64), _ CryptoStreamMode.Write) Dim sw As StreamWriter = New StreamWriter(cs) sw.Write(value) sw.Flush() cs.FlushFinalBlock() ms.Flush() '再轉換為一個字串 Return Convert.ToBase64String(ms.GetBuffer(), 0, ms.Length) End If End Function '標準的DES解密 Public Shared Function Decrypt(ByVal value As String) As String If value <> "" Then Dim cryptoProvider As DESCryptoServiceProvider = _ New DESCryptoServiceProvider() '從字串轉換為位元組組 Dim buffer As Byte() = Convert.FromBase64String(value) Dim ms As MemoryStream = New MemoryStream(buffer) Dim cs As CryptoStream = _ New CryptoStream(ms, cryptoProvider.CreateDecryptor(KEY_64, IV_64), _ CryptoStreamMode.Read) Dim sr As StreamReader = New StreamReader(cs) Return sr.ReadToEnd() End If End Function 'TRIPLE DES加密 Public Shared Function EncryptTripleDES(ByVal value As String) As String If value <> "" Then Dim cryptoProvider As TripleDESCryptoServiceProvider = _ New TripleDESCryptoServiceProvider() Dim ms As MemoryStream = New MemoryStream() Dim cs As CryptoStream = _ New CryptoStream(ms, cryptoProvider.CreateEncryptor(KEY_192, IV_192), _ CryptoStreamMode.Write) Dim sw As StreamWriter = New StreamWriter(cs) sw.Write(value) sw.Flush() cs.FlushFinalBlock() ms.Flush() '再轉換為一個字串 Return Convert.ToBase64String(ms.GetBuffer(), 0, ms.Length) End If End Function 'TRIPLE DES解密 Public Shared Function DecryptTripleDES(ByVal value As String) As String If value <> "" Then Dim cryptoProvider As TripleDESCryptoServiceProvider = _ New TripleDESCryptoServiceProvider() '從字串轉換為位元組組 Dim buffer As Byte() = Convert.FromBase64String(value) Dim ms As MemoryStream = New MemoryStream(buffer) Dim cs As CryptoStream = _ New CryptoStream(ms, cryptoProvider.CreateDecryptor(KEY_192, IV_192), _ CryptoStreamMode.Read) Dim sr As StreamReader = New StreamReader(cs) Return sr.ReadToEnd() End If End Function End Class 上面我們將一組位元組初始化為密鑰,並且使用的是數字常量,如果你在實際應用中也這樣做,這些位元組一定要在0和255之間,這是一個位元組允許的範圍值。 三、建立一個Cookie的應用類 下面我們就建立一個簡單的類,來設定和擷取Cookies。 Public Class CookieUtil '設定COOKIE ***************************************************** 'SetTripleDESEncryptedCookie (只針對密鑰和Cookie資料) Public Shared Sub SetTripleDESEncryptedCookie(ByVal key As String, _ ByVal value As String) key = CryptoUtil.EncryptTripleDES(key) value = CryptoUtil.EncryptTripleDES(value) SetCookie(key, value) End Sub 'SetTripleDESEncryptedCookie (增加了Cookie資料的有效期間參數) Public Shared Sub SetTripleDESEncryptedCookie(ByVal key As String, _ ByVal value As String, ByVal expires As Date) key = CryptoUtil.EncryptTripleDES(key) value = CryptoUtil.EncryptTripleDES(value) SetCookie(key, value, expires) End Sub 'SetEncryptedCookie(只針對密鑰和Cookie資料) Public Shared Sub SetEncryptedCookie(ByVal key As String, _ ByVal value As String) key = CryptoUtil.Encrypt(key) value = CryptoUtil.Encrypt(value) SetCookie(key, value) End Sub 'SetEncryptedCookie (增加了Cookie資料的有效期間參數) Public Shared Sub SetEncryptedCookie(ByVal key As String, _ ByVal value As String, ByVal expires As Date) key = CryptoUtil.Encrypt(key) value = CryptoUtil.Encrypt(value) SetCookie(key, value, expires) End Sub 'SetCookie (只針對密鑰和Cookie資料) Public Shared Sub SetCookie(ByVal key As String, ByVal value As String) '編碼部分 key = HttpContext.Current.Server.UrlEncode(key) value = HttpContext.Current.Server.UrlEncode(value) Dim cookie As HttpCookie cookie = New HttpCookie(key, value) SetCookie(cookie) End Sub 'SetCookie(增加了Cookie資料的有效期間參數) Public Shared Sub SetCookie(ByVal key As String, _ ByVal value As String, ByVal expires As Date) '編碼部分 key = HttpContext.Current.Server.UrlEncode(key) value = HttpContext.Current.Server.UrlEncode(value) Dim cookie As HttpCookie cookie = New HttpCookie(key, value) cookie.Expires = expires SetCookie(cookie) End Sub 'SetCookie (只針對HttpCookie) Public Shared Sub SetCookie(ByVal cookie As HttpCookie) HttpContext.Current.Response.Cookies.Set(cookie) End Sub '擷取COOKIE ***************************************************** Public Shared Function GetTripleDESEncryptedCookieValue(ByVal key As String) _ As String '只對祕密金鑰加密 key = CryptoUtil.EncryptTripleDES(key) '擷取Cookie值 Dim value As String value = GetCookieValue(key) '解密Cookie值 value = CryptoUtil.DecryptTripleDES(value) Return value End Function Public Shared Function GetEncryptedCookieValue(ByVal key As String) As String '只對祕密金鑰加密 key = CryptoUtil.Encrypt(key) '擷取Cookie值 Dim value As String value = GetCookieValue(key) '解密Cookie值 value = CryptoUtil.Decrypt(value) Return value End Function Public Shared Function GetCookie(ByVal key As String) As HttpCookie '編碼密鑰 key = HttpContext.Current.Server.UrlEncode(key) Return HttpContext.Current.Request.Cookies.Get(key) End Function Public Shared Function GetCookieValue(ByVal key As String) As String Try '編碼在GetCookie裡完成 '擷取Cookie值 Dim value As String value = GetCookie(key).Value '解碼所儲存的值 value = HttpContext.Current.Server.UrlDecode(value) Return value Catch End Try End Function End Class 上面的設定功能中,有些功能附加提供了Cookie有效期間這個參數。不設定該參數,Cookie將只為瀏覽器會話才儲存在記憶體中。為了設定永久的Cookie,就需要設定有效期間參數。 上面我們對密鑰和Cookies值進行了編碼與解碼,其原因是Cookies與URLs有同樣的限制,字元“=”和“;”是保留的,不能使用。這在儲存加密後的資料時尤其重要,因為密碼編譯演算法將添加“=”,按所分配塊的大小來填滿該資料區塊。 好了,你會保護Cookies資料了吧? |