保存登錄信息的Cookie加密技術

来源:http://www.cnblogs.com/VectorZhang/archive/2016/04/23/5425283.html
-Advertisement-
Play Games

所有需要賬戶登錄的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

image

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

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 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 網站還在不斷開發中…


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ngx_http_upstream_module用於將多個伺服器定義成伺服器組,而由proxy_pass,fastcgi_pass等指令引用 (1)upstream name {...} 定義一個後端伺服器組,name為組名,只能用於http上下文中 (2) server address [para ...
  • sudo apt-get install shutter 然後配合系統快捷鍵,我定義的和qq的截屏一樣的。用著感覺很舒服。 ...
  • Debian系統的普通用戶需要安裝軟體時,往往會收到“Permission denied”的提示,這時候需要root許可權。那麼如何在不登陸超級管理員賬戶的前提下擁有root許可權呢?對於大多數Linux系統來說,我們可以通過“sudo”命令來獲取root許可權,或者通過“su”登陸超級管理員賬戶來進行各 ...
  • C#泛型是一種高復用性、安全和高效的技術,通過類型參數可以將參數的聲明、實現推遲到客戶代碼中。但是這種延遲卻降低了類型參數在泛型定義中的可操作性。例如資源釋放。 但是如果T實現了IDisposable介面,則上面代碼可能存在資源泄露的風險。但是由於不知道T是否實現了IDisposable介面,所以不 ...
  • 菜鳥要飛系列目錄 1.(菜鳥要飛系列)一,基於Asp.Net MVC5的後臺管理系統(前言) 2.(菜鳥要飛系列)二,基於Asp.Net MVC5的後臺管理系統(實現登陸功能) 3.(菜鳥要飛系列)三,基於Asp.Net MVC5的後臺管理系統(用戶的增刪改查功能) 4.(菜鳥要飛系列)四,基於As ...
  • 最近由於伺服器變更為Linux系統.MsSql for Linux什麼時候出來到生產環境使用還是要很長時間的.於是考慮使用Mysql資料庫,ORM使用EF.於是先踩下坑順便記錄一下,有需要的tx可以參考下.當你考慮使用EF連接Mysql的時候肯定是已經在網上搜了一堆教程.網上教程基本都是使用控制台做 ...
  • 現在在Windows下的應用程式開發,VS.Net占據了絕大多數的份額。因此很多以前搞VC++開發的人都轉向用更強大的VS.Net。在這種情況下,有很多開發人員就面臨瞭如何在C#中使用C++開發好的類的問題。下麵就用一個完整的實例來詳細說明怎樣用托管C++封裝一個C++類以提供給C#使用。 比如,現 ...
  • EF6開始提供了通過async和await關鍵字實現非同步查詢和保存的支持(.net 4.5及更高版本)。雖然不是所有的操作都能從非同步中獲益,但是耗時的操作、網路或IO密集型任務中,使用非同步可以提升客戶端性能和增強伺服器的擴展性。 本文將覆蓋一下主題: 實例演練非同步操作 創建模型 創建同步程式 改為異 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...