前言
上一篇記錄了如何在 Kestrel 中使用 HTTPS(SSL), 也是我們目前項目中實際使用到的。
資料安全往往是開發人員很容易忽略的一個部分,包括我自己。近兩年業內也出現了很多因為安全問題導致了很多嚴重事情發生,所以安全對我們開發人員很重要,我們要對我們的代碼的安全負責。
在工作中,我們常常會見到 encode,base64,sha256, rsa, hash,encryption, md5 等,一些人對他們還傻傻分不清楚,也不知道什麼時候使用他們,還有一些人認為MD5就是密碼編譯演算法。
在 ASP.NET Core 中,為資料保護相關提供了一批新的 API,包括加密解密機制,下面就讓我們來看看吧。
目錄
•加密,編碼,雜湊之間的區別
•資料保護(Data Protection)介紹
•ASP.NET Core 中的資料保護
•總結
編碼,加密,雜湊之間的區別
1、編碼
編碼是資訊從一種形式或格式轉換為另一種形式的過程,他們是可逆的。
如 url、base64、jsunicode、utf-8等等。
2、加密
加密是可逆的,類似於編碼也是把資料從一種形式轉換為另一種形式,它通過一個特定的加密的密匙,相對應的有解密的過程。加解密的演算法有2種:對稱式加密演算法和非對稱式加密演算法。
對稱:DES、AES、SM1、RC4 等等。
非對稱:RSA、ECC、SM2 等等。
3、雜湊
又叫"散列",就是把任意長度的資料轉換成固定長度的“指紋”,這個過程是無法復原的。而且只要輸入發生改變,輸出的 hash值也會有很大不同。
它還有一個特性是相同的輸入總是有相同的結果, 這種特性恰好合適用來用來儲存密碼。
如:MD5、SHA256, SHA512, RipeMD, WHIRLPOOL等等。
資料保護(Data Protection)介紹
在看資料保護官方文檔的時候,微軟的文檔是這樣寫的,大致意思就是他們基於幾點需求,要開發一套資料保護的庫以便用來給受信任的用戶端和不受信任的用戶端來使用。這幾點要求就是:
1、真實性、完整性
舉了一個身分識別驗證cookie的例子,就是服務端產生了一個包含xyz許可權的token,然後會在將來的某個時間到期,這個時候就需要重新請求產生一個,怎麼樣來保證請求的token不是被篡改過的。
2、機密性
伺服器要保證請求是受信任的,所以就需要一些包含特定作業環境的資訊,比如一個路徑,一個許可權或者一個控制代碼或者其他的一些東西特定於伺服器的東西,這些資訊不應該透漏給不受信任的用戶端,也就是說類似於私密金鑰。
3、隔離性
然後就是要求做成一個組件,並且這個組件具有獨立性,可以不依賴於系統中的其他組件。如一個bearer token的組件,它要使用這個組件的話,也不需要引用anti-CSRF這種機制了。
再進一步的縮小需求範圍,加密的資料不需要在系統之外的其他系統中使用,另外處理速度要儘可能的快,因為每一次web請求都會使用加密組件一次或者多次。
基於以上要求,微軟提出來可以使用密碼學,因為這是一個典型的密碼學應用的情境。確實這是一個密碼學的應用情境,並且是一個非對稱式加密演算法的情境。但是大家都知道,非對稱式加密是由一個公開金鑰和私密金鑰用來保證安全性的,即使公開金鑰遭泄露,整個通訊仍然是安全的,這就是它比對稱式加密的好處。但是非對稱式加密也是有缺點的,就是加密和解密花費的時間長,速度慢。
但是上面的要求又是需要速度儘可能快,怎麼辦呢? 於是微軟的工程師們想出了可以通過精簡併且最佳化非對稱式加密機制,來達到這個要求。因為不需要跨系統或者跨語言什麼的,所以也不需要什麼協議之類的,這就給最佳化帶來了更多的可能性。
到這裡,我就想,如果讓我來基於以上幾點來設計開發這樣一個系統,我應該怎麼樣設計?怎麼樣達到要求?
帶著這個問題,我們來進一步看看微軟是怎麼樣做的吧?
下面是一些總結的設計原則 :
1、配置應該盡量的簡單,預設情況下應該可以零配置,開發人員可以直接運行。
2、提供一個簡單的API,應該容易使用,並且不會輕易用錯。
3、開發人員不需要專門學習怎麼樣管理這些鑰(公開金鑰,私密金鑰),系統應該自動的選擇演算法和管理鑰的生命週期。理想情況下開發人員都不應該訪問這些鑰的原始檔案。
4、鑰應該是受保護的,不會被遠程調用到。系統應該有一個自動保護機制並且可以自動應用。
如果讓我設計這樣一個庫,我可能不會想到這麼多,也許只會想到前3點。
再看一下針對的受眾群體:
1、應用程式開發人員和架構開發人員(不需要學習任何知識)。
2、應用開發人員和系統管理員(不使用預設配置,只是設定一些路徑等)。
3、針對具有更高安全意識的開發人員提供可擴充api,或特定需求擴充(需要重寫系統的組件,有一些獨特的需求)。
以上,可以看到微軟在開發一個組件的時候對問題的分析,也許我們可以從中學到一些東西。
ASP.NET Core 中的資料保護
Web應用程式中經常需要儲存一些敏感性資料(如使用者密碼),Windows 系統為傳統型程式提供了DPAPI用來使用,但是並不適用於 Web 系統。ASP.NET Core提供了一套簡單易用的API 用來保護資料。
ASP.NET Core 中,資料保護主要是用來給服務端設計的,用來替換ASP.NET 1.x-4.x中的,machineKey主要是用來保證使用Form身分識別驗證時Cookie資料的加密解密,以確保不會被修改。或者ViewState資料的加密解密不被篡改,以及對session狀態標識進行驗證。
先看一下最簡單的使用方法:
using System;using Microsoft.AspNetCore.DataProtection;using Microsoft.Extensions.DependencyInjection;public class Program{ public static void Main(string[] args) { // 添加資料保護到服務中 var serviceCollection = new ServiceCollection(); serviceCollection.AddDataProtection(); var services = serviceCollection.BuildServiceProvider(); // 從DI中建立一個MyClass的執行個體 var instance = ActivatorUtilities.CreateInstance<MyClass>(services); instance.RunSample(); } public class MyClass { IDataProtector _protector; // 參數 'provider' 來自 DI public MyClass(IDataProtectionProvider provider) { _protector = provider.CreateProtector("Contoso.MyClass.v1"); } public void RunSample() { Console.Write("Enter input: "); string input = Console.ReadLine(); // 加密 string protectedPayload = _protector.Protect(input); Console.WriteLine($"Protect returned: {protectedPayload}"); // 解密 string unprotectedPayload = _protector.Unprotect(protectedPayload); Console.WriteLine($"Unprotect returned: {unprotectedPayload}"); } }}/* * 輸出: * * Enter input: Hello world! * Protect returned: CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ * Unprotect returned: Hello world! */
在CreateProtector("Contoso.MyClass.v1")中,參數“Contoso.MyClass.v1”可以理解為一個公開金鑰,因為 ASP.NET Core Data Protection 是非對稱式加密(見前面介紹),所以系統中應該還有一個密鑰,那麼此處的密鑰 ASP.NET Core 在系統內部幫你維護了。
讀到這裡,有同學可能會問了,那系統中是如何幫我維護我的密鑰的呢? 我們不妨先來做一個測試。
首先,我在我的開發環境中,先把上面的程式中的解密部分代碼注釋掉,然後運行上面的程式,輸入一個“Hello World!” ,得到了一個加密的字串CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ(略寫)。
然後我把同樣的程式拷貝到另外一台開發環境的機器上,然後把上面的加密部分代碼注釋掉,使用第一步產生的CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ來解密,注意這兩步中我們都使用 "Contoso.MyClass.v1" 來做為公開金鑰。
運行程式,查看結果:
程式拋出了一個“System.Security.Cryptography.CryptographicException”異常的結果。
為什麼呢? 這是因為每一台機器都有一個自有的私密金鑰,由於在解密的過程中,這個私密金鑰是不同的,所以解密失敗,拋出了一個異常。
私密金鑰
私密金鑰存放在哪裡呢?
1、如果程式寄宿在 Microsoft Azure下,儲存在“%HOME%\ASP.NET\DataProtection-Keys” 檔案夾。
2、如果程式寄宿在IIS下,它被儲存在HKLM註冊表的ACLed特殊註冊表鍵,並且只有背景工作處理序可以訪問,它使用windows的DPAPI加密。
3、如果目前使用者可用,即win10或者win7中,它儲存在“%LOCALAPPDATA%\ASP.NET\DataProtection-Keys”檔案夾,同樣使用的windows的DPAPI加密。
4、如果這些都不符合,那麼也就是私密金鑰是沒有被持久化的,也就是說當進程關閉的時候,產生的私密金鑰就丟失了。
下面是博主機器上的私密金鑰檔案:
一個xml設定檔,位於C:\Users\使用者名稱\AppData\Local\ASP.NET\DataProtection-Keys檔案夾,名為:key-c37e3ed9-fbb5-47bc-9e8c-128afaf1c6d9.xml,內容如下:
<?xml version="1.0" encoding="utf-8"?><key id="c37e3ed9-fbb5-47bc-9e8c-128afaf1c6d9" version="1"> <creationDate>2016-08-15T05:21:16.7925949Z</creationDate> <activationDate>2016-08-15T05:21:16.7165905Z</activationDate> <expirationDate>2016-11-13T05:21:16.7165905Z</expirationDate> <descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"> <descriptor> <encryption algorithm="AES_256_CBC" /> <validation algorithm="HMACSHA256" /> <encryptedSecret decryptorType="Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor, Microsoft.AspNetCore.DataProtection, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60" xmlns="http://schemas.asp.net/2015/03/dataProtection"> <encryptedKey xmlns=""> <!-- This key is encrypted with Windows DPAPI. --> <value>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAArS6GBZu5C024S8VcNDckGgAAAAACAAAAAAAQZgAAAAEAACAAAABBUO4j0CscEZsdcHDAStXnDvtx+zFucmsG90sdhyjfgQAAAAAOgAAAAAIAACAAAABGr9fgvZkLAlgIZkGym5uLiufpaEcuVsp35+J96ItTYlABAADEZxVArK0QtxufuaRt/kVR2ZBZEoLhlYJ44BhvQDd6b9tN0L9Y7W2eeBPBefcZaGZk5xILwZYI5box9omwC/mp8t9wopVaratjZuNs21Al+JzxS+PeV9X0iPtRyfx2K7DJYOUT6IqoFR2ykL5MI9jvkIbUxcQOs0BKOwAHl4yAlYF2tR8pz1FkXKqZafovc11aOZeZhkfd2hiA53tan94bQOP43Z4HF+QWSazrq5IIqdFSOyZQemWL9Z7eYyoNpEktf3eGZQu/KBOg/BH5yizWa+6b7RLcEX6JdQ2/jpmnHNl+HPMIah3UZV0mRfAE2j58cUjosnV+LDQZoLn4OP70YWtO/tTBc4tsEY3n/WboL4PgPPmQ+2jfd/zmEQIon+4d7TY+mGh4c6wXAmAZF517UAHQMC1icx4HSJC8DTuWPlINihPyufejuPmLqW6CW8NAAAAA7ziObXv+Ax4Mm0AtZiGw0/IepDv/gJSxhEwLIDhfvQIQJv//G500EYtIbZJW6sWit//ypfjrUZYglHgKV+GpbA==</value> </encryptedKey> </encryptedSecret> </descriptor> </descriptor></key>
檔案包含一個建立日期,一個到期日期。間隔為90天,當90天之後密鑰就會失效,系統將自動產生一個新的密鑰並設定新的密鑰作為活動的密鑰。只要已到期的密鑰還存在於系統上,你仍然可以解密任何受保護的資料。
文章不宜太長,下篇再接著寫。
總結
這篇文章算是對ASP.NET Core Data Protection做了一個大致的介紹,並且包含了一個簡單的使用方法。 在實際使用過程中,其實很多組件內部都會使用到它,比如Session中介軟體,Identity中介軟體,Authercation中介軟體等等,對於普通開發人員在編碼的時候可能不會用到,但是在做系統分布式部署的時候如果你不瞭解這個機制可能就會遇到麻煩了(詳見蟋蟀部落格的這篇文章),所以還是可以期待一下下文,更加深入的瞭解它,掌握它。
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。