前言
上篇主要是對 ASP.NET Core 的 Data Protection 做了一個簡單的介紹,本篇主要是介紹一下API及使用方法。
API 介面
ASP.NET Core Data Protectio 主要對普通開發人員提供了兩個介面,IDataProtectionProvider 和 IDataProtector。
我們先看一下這兩個介面的關係:
namespace Microsoft.AspNetCore.DataProtection{ // // 摘要: // An interface that can provide data protection services. public interface IDataProtector : IDataProtectionProvider { byte[] Protect(byte[] plaintext); byte[] Unprotect(byte[] protectedData); }}
可以看到,IDataProtector繼承自IDataProtectionProvider ,並且提供了兩個方法 Protect 和 Unprotect ,從命名來看,一個是加密,一個是解密。而他們的簽名都是傳入一個byte數組,這也就意味著他們可以加密和解密一切對象。返回的也是byte數組,也就是說在實際的使用過程中,我們應該自己添加或者使用系統的一些擴充方法來具體化我們的需求。
我們再看一下IDataProtectionProvider介面:
namespace Microsoft.AspNetCore.DataProtection{ public interface IDataProtectionProvider { IDataProtector CreateProtector(string purpose); }}
IDataProtectionProvider提供了一個方法,通過傳入一個 purpose字串(見後面詳細介紹)來產生一個IDataProtector介面對象。
從這個介面的命名來看,它以Provider結尾,也就是說這部分我們可以實現自己的一套加解密的東西。
我們在閱讀微軟項目的原始碼的時候,經常看一些以xxxxProvider結尾的對象,那麼它的職責是什麼,同時扮演什麼樣的角色呢?
其實這是微軟專門為ASP.NET設計的一個設計模式,叫Provider Model設計模式,也可以說它是由微軟發明的,它不屬於23種設計模式中的一種,從功能上來看的話,應該是工廠和策略的結合體。自ASP.NET 2.0開始,微軟就開始引入這種設計模式,最開始主要是用於實現應用程式的配置的多個實現。比如開發人員最熟悉的web.config中, 針對於資料庫連接字串的配置, 還有二進位,再比如XML啊等等很多,現在其他地方這種模式也用的越來越多起來。
再來說一下CreateProtector方法簽名中的 purpose 這個字串,在上一篇博文中為了讀者好理解,我把傳入的purpose說成可以理解為一個公開金鑰,其實這個說法是不嚴謹的,可以理解為一個標識,指示當前Protector的用途。
在使用IDataProtector的時候,會發現它還有一些擴充方法位於Microsoft.AspNetCore.DataProtection命名空間下:
public static class DataProtectionCommonExtensions{ public static IDataProtector CreateProtector(this IDataProtectionProvider provider, IEnumerable<string> purposes); public static IDataProtector CreateProtector(this IDataProtectionProvider provider, string purpose, params string[] subPurposes); public static IDataProtector GetDataProtector(this IServiceProvider services, IEnumerable<string> purposes); public static IDataProtector GetDataProtector(this IServiceProvider services, string purpose, params string[] subPurposes); public static string Protect(this IDataProtector protector, string plaintext); public static string Unprotect(this IDataProtector protector, string protectedData);}
可以看到,CreateProtector還提供了可以傳多個purpose的方法(IEnumerable,params string[]),為什麼會有這種需求呢?
其實DataProtector是有階層的,再看一下IDataProtector介面,它自身也實現了IDataProtectionProvider介面,就是說IDataProtector自身也可以再建立IDataProtector。
舉個例子:我們在做一個訊息通訊的系統,在訊息通訊的過程中,需要對使用者的會話進行加密,我們使用CreateProtector("Security.BearerToken")加密。但是加密的時候並不能保證訊息是不受信任的用戶端發過來的,所以想到了CreateProtector("username")來進行加密,這個時候假如有一個使用者的使用者名稱叫“Security.BearerToken”,那麼就和另外一個使用Security.BearerToken作為標示的 Protector 衝突了,所以我們可以使用
CreateProtector([ “Security.BearerToken”, “User: username” ])這種方式。它相當於
provider.CreateProtector(“Security.BearerToken).CreateProtector(“User: username”)。 意思就是先建立一個Protector叫“Security.BearerToken”,然後再在purpose1下建立一個名為“User: username”的Protector。
使用者密碼雜湊
在Microsoft.AspNetCore.Cryptography.KeyDerivation命名空間下提供了一個KeyDerivation.Pbkdf2方法用來對使用者密碼進行雜湊。
具有生命週期限制的加密
有些時候,我們需要一些具有到期或者到期時間的加密字串,比如一個使用者在找回密碼的時候,我們向使用者的郵箱發送一封帶有重設命令的一封郵件,這個重設命令就需要有一個到期時間了,超過這個到期時間後就失效,在以前我們可能需要向資料庫儲存一個時間來標記發送時間,然後再解密對比和資料庫的時間差來驗證。
現在我們不需要這麼做了,ASP.NET Core 預設提供了一個介面叫 ITimeLimitedDataProtector ,我們先看一下這個介面的定義:
CreateProtector(string purpose) : ITimeLimitedDataProtector This API is similar to the existing IDataProtectionProvider.CreateProtector in that it can be used to create purpose chains from a root time-limited protector.Protect(byte[] plaintext, DateTimeOffset expiration) : byte[]Protect(byte[] plaintext, TimeSpan lifetime) : byte[]Protect(byte[] plaintext) : byte[]Protect(string plaintext, DateTimeOffset expiration) : stringProtect(string plaintext, TimeSpan lifetime) : stringProtect(string plaintext) : string
ITimeLimitedDataProtector提供了數個重載方法用來設定帶有生命週期的加密方法,使用者可以通過Date TimeOffset,TimeSpan等參數來設定時間。
有對應的加密,就有相對應的解密方法,在這裡就不詳細介紹了。有興趣的同學可以去看一下官方文檔。
配置資料保護
在我們的 ASP.NET Core 啟動並執行時候,系統會基於當前機器的運行環境預設配置一些關於 Data Protection 的東西,但是有些時候可能需要對這些配置做一些改變,比如在分布式部署的時候,在上一篇博文的末尾也提到過,下面就來看一下具體怎麼配置的吧。
上篇文章已經提到過,我們通過以下方式來把 Data Protection 註冊到服務中:
public void ConfigureServices(IServiceCollection services){ services.AddDataProtection();}
其中AddDataProtection 返回的是一個 IDataProtectionBuilder 介面,這個介面提供了一個擴充方法PersistKeysToFileSystem() 來儲存私密金鑰。可以通過它傳入一個路徑來指定私密金鑰儲存的位置:
public void ConfigureServices(IServiceCollection services){ services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));}
可以傳入一個共用資料夾,來儲存私密金鑰,這樣在不同機器的私密金鑰就可以儲存到一個位置了。可以通過此種方式在分布式部署的時候,隔離開了機器的差異化。
如果你覺得不安全,還可以配置一個X.509認證來,進行加密:
public void ConfigureServices(IServiceCollection services){ services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\")) .ProtectKeysWithCertificate("thumbprint");}
上篇文章講過,Data Protection 的預設儲存時間是90天,你可以通過以下方式來修改預設的儲存時間:
public void ConfigureServices(IServiceCollection services){ services.AddDataProtection() .SetDefaultKeyLifetime(TimeSpan.FromDays(14));}
預設情況下,即使使用相同的物理密鑰庫,Data Protection 也會把不同的應用程式隔離開,因為這樣可以防止從一個應用程式擷取另外一個應用程式的密鑰。所以如果是相同的應用程式,可以設定相同的應用程式名稱:
public void ConfigureServices(IServiceCollection services){ services.AddDataProtection() .SetApplicationName("my application");}
有時候需要禁用應用程式產生密鑰,或者是說我只有一個程式用來產生或者管理密鑰,其他程式只是負責讀的話,那麼可以這樣:
public void ConfigureServices(IServiceCollection services){ services.AddDataProtection() .DisableAutomaticKeyGeneration();}
修改密碼編譯演算法
可以使用UseCryptographicAlgorithms方法來修改ASP.NET Core Data Protection的預設密碼編譯演算法,如下:
services.AddDataProtection() .UseCryptographicAlgorithms(new AuthenticatedEncryptionSettings() { EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC, ValidationAlgorithm = ValidationAlgorithm.HMACSHA256 });
總結:
本篇主要是介紹了一些常用的API, 下篇介紹一些進階的用法。
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。