深度解析用于保存登錄信息的Cookie加密技術

在這個快節(jié)奏的生活里,我們要求各種操作都要快捷方便!登錄某些論壇或者購物網站的時候,即便您再喜歡某一個帖子或者某一件商品。但是如果登錄的步驟過于繁瑣,可能就會打消我們的熱情。所以,現在網站都可以在一段時間內保存您的登錄名和密碼,讓您在需要下次訪問的時候,可以減少登錄的繁瑣步驟。這個就需要使用到Cookie加密技術!

用Cookie或者Session來保存登錄信息已經是一種比較成熟的技術。但是對于賬戶信息如果把明文放在Cookie里面顯然是非常危險的。Cookie 是以key-value的形式存數據。對于賬戶信息而言最簡單的是 UserName 和 Password。如果以明文的形式放到Cookie 比如:UserName=fakeUser ??Password=fakePsd考慮到安全性的問題,顯然沒有任何website會這樣做。那么是否可以把這幾個字段都加密呢?

對 Key 的加密

對key字段像UserName, Password只需要在Server端加密并保存即可,甚至都無需還原成明文。

public static string MD5Hash(string input)

{

byte[ ] data = Encoding.UTF8.GetBytes(input.Trim( ).ToLowerInvariant( ));

using (var md5 = new MD5CryptoServiceProvider( ))

{ ?data = md5.ComputeHash(data); ?}

var ret = new StringBuilder( );

foreach (byte b in data)

{ ?ret.Append(b.ToString("x2").ToLowerInvariant( ));}

return ret.ToString( );

}

例如計算出UserName 和 Password的 MD5 hash 值,Cookie形式就可以表示成

ee11cbb19052e40b07aac0ca060c23ee=fakeUser

5f4dcc3b5aa765d61d8327deb882cf99=fakePsd

相比沒有加密前安全性是不是高了那么一點點,但這肯定還是不夠。我們最終的目標是對所有字段加密。

對Value的加密

對value字段加密就不能是單向的,試想一下如果在Server端對用戶名加密放到Cookie再傳到Client端, 看起來OK. 當Client端的cookie再傳回Server端時,如果不能解密Encode后的用戶名那么Cookie就等于失效了。

一個非常簡單的算法就是用過異或來實現加密解密,比如提供一個秘鑰 X,

encode_data = data ^ X

decode_data = encode_data ^ X

則 data == decode_data.

目前 .NET 提供不了不少對稱加密算法都直接以dll 的形式給出了。.NET 中提供的對稱加密算法都繼承基類SymmetricAlgorithm

深度解析用于保存登錄信息的Cookie加密技術

具體代碼可以直接調用他們的子類像

TripleDESCryptoServiceProvider

RijndaelManaged

MSDN 上已經提供了的代碼案例,這里就不再給出Test Sample,為了能夠靈活的運用到項目中本人就封裝了一些接口。

// 定義加密解密的接口

public interface IEncryptionProvider

{

byte[?] Key { get; }

byte [ ] IV { get; }

Encoding Encoding { get; }

string Encrypt(string data);

string Decrypt(string encodeData);

}

//加密解密抽象基類

public abstract class BaseEncryptionProvider : IEncryptionProvider

{

protected byte[ ] _keyBytes;

protected byte [ ] _IVBytes;

public byte[ ] Key

{

get ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?if (this._keyBytes == null)

{ ? ? ? ? ? ? ? ? ??this.GenerateKeyIV(); ? ? ? ? ? ? ??} ? ? ? ? ? ? ? ?

return this._keyBytes; ? ? ? ? ? ?

} ? ? ? ?

? ? ? } ? ? ?

//異或加密算法類

public class EOREncryptionProvider : BaseEncryptionProvider

{

private string _key;

public EOREncryptionProvider(string key)

{

if (string.IsNullOrEmpty(key))

{throw new ArgumentNullException("key");}

this._key = key;

}

public override void GenerateKeyIV()

{ ? ? ? ? ? ?this._keyLength - 1];}?}

return dataBytes;

}

protected override byte[ ]

DecryptImpl(byte[ ] dataBytes)

{

int dataLength = dataBytes.Length;

int IVLength = this.IV.Length;

for (var i = 0; i < dataLength; i++)

{?if (i < IVLength)

{ dataBytes[i] ^= this.IV[i]; }

else { dataBytes[i] ^= this.IV[IVLength - 1]; }

}

return dataBytes;}

}

// .Net 內置加密算法的封裝   
 
public class SymmetricAlgoEncryptionProvider : BaseEncryptionProvider   
 
{
        
private SymmetricAlgorithm _symmetricAlgorithm;  
      
public SymmetricAlgoEncryptionProvider(SymmetricAlgorithm providerImpl)       

{            if (providerImpl == null)            

{                throw new ArgumentNullException("providerImpl");            }            

this._symmetricAlgorithm = providerImpl;            

this._symmetricAlgorithm.Padding = PaddingMode.ISO10126;        

}        

protected override byte[] EncryptImpl(byte[] bytes)        

{            byte[ ] encryptedData;            

using (var input = new MemoryStream(bytes))            

using (var output = new MemoryStream())            

{                

var encryptor = this._symmetricAlgorithm.CreateEncryptor(this.Key, this.IV);                

using (var cryptStream = new CryptoStream(output, encryptor, CryptoStreamMode.Write))

{                    var buffer = new byte[1024];                    var read = input.Read(buffer, 0, buffer.Length);                    while (read > 0)                    

{                        cryptStream.Write(buffer, 0, read);                        read = input.Read(buffer, 0, buffer.Length);                    }                    

cryptStream.FlushFinalBlock();                    encryptedData = output.ToArray();                

}            
     }            

return encryptedData;        }        

protected override byte[ ] 

DecryptImpl(byte[ ] bytes)        

{            byte[] result;            

using (var input = new MemoryStream(bytes))            

using (var output = new MemoryStream())            

{                

var decryptor = this._symmetricAlgorithm.CreateDecryptor(this.Key, this.IV);                

using (var cryptStream = new CryptoStream(input, decryptor, CryptoStreamMode.Read))                

{                    var buffer = new byte[1024];                    var read = cryptStream.Read(buffer, 0, buffer.Length);                    while (read > 0)                    
{                        output.Write(buffer, 0, read);                        read = cryptStream.Read(buffer, 0, buffer.Length);                    }                    
cryptStream.Flush();                    

result = output.ToArray();                

}            
   }            

return result;       }        

public override void GenerateKeyIV()        

{            this._symmetricAlgorithm.GenerateKey();            

this._symmetricAlgorithm.GenerateIV();            

this._keyBytes = this._symmetricAlgorithm.Key;            

this._IVBytes = this._symmetricAlgorithm.IV;       
 
}    

   }

最后可以這樣調用

static void Main(string[] args)  
      
{  
          
IEncryptionProvider provider = new EOREncryptionProvider("this is the key");            

string data = "fakeUser";            

string encodeData = provider.Encrypt(data);            

Console.WriteLine("encodeData:{0}", encodeData);            

string decodeData = provider.Decrypt(encodeData);           

 Console.WriteLine("decodeData:{0}", decodeData);            

provider = new SymmetricAlgoEncryptionProvider(new TripleDESCryptoServiceProvider());            

encodeData = provider.Encrypt(data);            

Console.WriteLine("encodeData:{0}", encodeData);            

decodeData = provider.Decrypt(encodeData);            

Console.WriteLine("decodeData:{0}", decodeData);        

}

最后Cookie形式就可以表示成

ee11cbb19052e40b07aac0ca060c23ee=EgkCFnUaFlI

5f4dcc3b5aa765d61d8327deb882cf99=vDwCZGvezDfudh91hRsiow