所有需要賬戶登錄的website 基本都會想到這樣一個問題, 如何保持用戶在一定時間內登錄有效。 最近本人就在項目中遇到這樣的需求,某些頁面只能Admin賬戶登錄後訪問, 當登錄Admin賬戶後如何才能保持登錄信息呢? 用Cookie或者Session來保存登錄信息已經是一種比較成熟的技術。但是對於 ...
所有需要賬戶登錄的website 基本都會想到這樣一個問題, 如何保持用戶在一定時間內登錄有效。
最近本人就在項目中遇到這樣的需求,某些頁面只能Admin賬戶登錄後訪問, 當登錄Admin賬戶後如何才能保持登錄信息呢?
用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
具體代碼可以直接調用他們的子類像
TripleDESCryptoServiceProvider
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 byte[] IV { get { if (this._IVBytes == null) { this.GenerateKeyIV(); } return this._IVBytes; } } private Encoding _encoding; public Encoding Encoding { get { return this._encoding ?? Encoding.UTF8; } set { this._encoding = value; } } public string Encrypt(string data) { if (string.IsNullOrEmpty(data)) { throw new ArgumentNullException("data"); } byte[] bytes = this.Encoding.GetBytes(data); var encodedBytes = this.EncryptImpl(bytes); return this.PostEncrypt(encodedBytes); } public string Decrypt(string encodeData) { if (string.IsNullOrEmpty(encodeData)) { throw new ArgumentNullException("encodeData"); } var bytes = this.PreDecrypt(encodeData); var decodeBytes = this.DecryptImpl(bytes); return this.Encoding.GetString(decodeBytes); } //加密演算法的實現函數 protected abstract byte[] EncryptImpl(byte[] bytes); //解密演算法的實現函數 protected abstract byte[] DecryptImpl(byte[] bytes); public virtual string PostEncrypt(byte[] bytes) { return System.Convert.ToBase64String(bytes); } public virtual byte[] PreDecrypt(string input) { return System.Convert.FromBase64String(input); } public abstract void GenerateKeyIV(); }
//異或加密演算法類 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._keyBytes = this.Encoding.GetBytes(this._key); this._IVBytes = this.Encoding.GetBytes(this._key); } //考慮到秘鑰長度以及數據長度等因素 具體實現演算法多種多樣 protected override byte[] EncryptImpl(byte[] dataBytes) { int dataLength = dataBytes.Length; int keyLength = this.Key.Length; for (var i = 0; i < dataLength; i++) { if (i < keyLength) { dataBytes[i] ^= this.Key[i]; } else { dataBytes[i] ^= this.Key[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
歡迎訪問我的個人網站 51zhang.net 網站還在不斷開發中…