前言
上一篇記錄了如何在 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中間件等等,對於普通開發人員在編碼的時候可能不會用到,但是在做系統分布式部署的時候如果你不了解這個機制可能就會遇到麻煩了(詳見蟋蟀博客的這篇文章),所以還是可以期待一下下文,更加深入的了解它,掌握它。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。