ASP.NET Core 數(shù)據(jù)保護(Data Protection)上篇
前言
上一篇記錄了如何在 Kestrel 中使用 HTTPS(SSL), 也是我們目前項目中實際使用到的。
數(shù)據(jù)安全往往是開發(fā)人員很容易忽略的一個部分,包括我自己。近兩年業(yè)內(nèi)也出現(xiàn)了很多因為安全問題導(dǎo)致了很多嚴(yán)重事情發(fā)生,所以安全對我們開發(fā)人員很重要,我們要對我們的代碼的安全負(fù)責(zé)。
在工作中,我們常常會見到 encode,base64,sha256, rsa, hash,encryption, md5 等,一些人對他們還傻傻分不清楚,也不知道什么時候使用他們,還有一些人認(rèn)為MD5就是加密算法。
在 ASP.NET Core 中,為數(shù)據(jù)保護相關(guān)提供了一批新的 API,包括加密解密機制,下面就讓我們來看看吧。
目錄
•加密,編碼,哈希之間的區(qū)別
•數(shù)據(jù)保護(Data Protection)介紹
•ASP.NET Core 中的數(shù)據(jù)保護
•總結(jié)
編碼,加密,哈希之間的區(qū)別
1、編碼
編碼是信息從一種形式或格式轉(zhuǎn)換為另一種形式的過程,他們是可逆的。
如 url、base64、jsunicode、utf-8等等。
2、加密
加密是可逆的,類似于編碼也是把數(shù)據(jù)從一種形式轉(zhuǎn)換為另一種形式,它通過一個特定的加密的密匙,相對應(yīng)的有解密的過程。加解密的算法有2種:對稱加密算法和非對稱加密算法。
對稱:DES、AES、SM1、RC4 等等。
非對稱:RSA、ECC、SM2 等等。
3、哈希
又叫"散列",就是把任意長度的數(shù)據(jù)轉(zhuǎn)換成固定長度的“指紋”,這個過程是不可逆的。而且只要輸入發(fā)生改變,輸出的 hash值也會有很大不同。
它還有一個特性是相同的輸入總是有相同的結(jié)果, 這種特性恰好合適用來用來保存密碼。
如:MD5、SHA256, SHA512, RipeMD, WHIRLPOOL等等。
數(shù)據(jù)保護(Data Protection)介紹
在看數(shù)據(jù)保護官方文檔的時候,微軟的文檔是這樣寫的,大致意思就是他們基于幾點需求,要開發(fā)一套數(shù)據(jù)保護的庫以便用來給受信任的客戶端和不受信任的客戶端來使用。這幾點要求就是:
1、真實性、完整性
舉了一個身份驗證cookie的例子,就是服務(wù)端生成了一個包含xyz權(quán)限的token,然后會在將來的某個時間過期,這個時候就需要重新請求生成一個,怎么樣來保證請求的token不是被篡改過的。
2、機密性
服務(wù)器要保證請求是受信任的,所以就需要一些包含特定操作環(huán)境的信息,比如一個路徑,一個權(quán)限或者一個句柄或者其他的一些東西特定于服務(wù)器的東西,這些信息不應(yīng)該透漏給不受信任的客戶端,也就是說類似于私鑰。
3、隔離性
然后就是要求做成一個組件,并且這個組件具有獨立性,可以不依賴于系統(tǒng)中的其他組件。如一個bearer token的組件,它要使用這個組件的話,也不需要引用anti-CSRF這種機制了。
再進一步的縮小需求范圍,加密的數(shù)據(jù)不需要在系統(tǒng)之外的其他系統(tǒng)中使用,另外處理速度要盡可能的快,因為每一次web請求都會使用加密組件一次或者多次。
基于以上要求,微軟提出來可以使用密碼學(xué),因為這是一個典型的密碼學(xué)應(yīng)用的場景。確實這是一個密碼學(xué)的應(yīng)用場景,并且是一個非對稱加密算法的場景。但是大家都知道,非對稱加密是由一個公鑰和私鑰用來保證安全性的,即使公鑰遭泄露,整個通訊仍然是安全的,這就是它比對稱加密的好處。但是非對稱加密也是有缺點的,就是加密和解密花費的時間長,速度慢。
但是上面的要求又是需要速度盡可能快,怎么辦呢? 于是微軟的工程師們想出了可以通過精簡并且優(yōu)化非對稱加密機制,來達到這個要求。因為不需要跨系統(tǒng)或者跨語言什么的,所以也不需要什么協(xié)議之類的,這就給優(yōu)化帶來了更多的可能性。
到這里,我就想,如果讓我來基于以上幾點來設(shè)計開發(fā)這樣一個系統(tǒng),我應(yīng)該怎么樣設(shè)計?怎么樣達到要求?
帶著這個問題,我們來進一步看看微軟是怎么樣做的吧?
下面是一些總結(jié)的設(shè)計原則 :
1、配置應(yīng)該盡量的簡單,默認(rèn)情況下應(yīng)該可以零配置,開發(fā)人員可以直接運行。
2、提供一個簡單的API,應(yīng)該容易使用,并且不會輕易用錯。
3、開發(fā)人員不需要專門學(xué)習(xí)怎么樣管理這些鑰(公鑰,私鑰),系統(tǒng)應(yīng)該自動的選擇算法和管理鑰的生命周期。理想情況下開發(fā)人員都不應(yīng)該訪問這些鑰的原始文件。
4、鑰應(yīng)該是受保護的,不會被遠(yuǎn)程調(diào)用到。系統(tǒng)應(yīng)該有一個自動保護機制并且可以自動應(yīng)用。
如果讓我設(shè)計這樣一個庫,我可能不會想到這么多,也許只會想到前3點。
再看一下針對的受眾群體:
1、應(yīng)用程序開發(fā)人員和框架開發(fā)人員(不需要學(xué)習(xí)任何知識)。
2、應(yīng)用開發(fā)人員和系統(tǒng)管理員(不使用默認(rèn)配置,只是設(shè)定一些路徑等)。
3、針對具有更高安全意識的開發(fā)人員提供可擴展api,或特定需求擴展(需要重寫系統(tǒng)的組件,有一些獨特的需求)。
以上,可以看到微軟在開發(fā)一個組件的時候?qū)栴}的分析,也許我們可以從中學(xué)到一些東西。
ASP.NET Core 中的數(shù)據(jù)保護
Web應(yīng)用程序中經(jīng)常需要存儲一些敏感數(shù)據(jù)(如用戶密碼),Windows 系統(tǒng)為桌面程序提供了DPAPI用來使用,但是并不適用于 Web 系統(tǒng)。ASP.NET Core提供了一套簡單易用的API 用來保護數(shù)據(jù)。
ASP.NET Core 中,數(shù)據(jù)保護主要是用來給服務(wù)端設(shè)計的,用來替換ASP.NET 1.x-4.x中的,machineKey主要是用來保證使用Form身份驗證時Cookie數(shù)據(jù)的加密解密,以確保不會被修改。或者ViewState數(shù)據(jù)的加密解密不被篡改,以及對session狀態(tài)標(biāo)識進行驗證。
先看一下最簡單的使用方法:
using System; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; public class Program { public static void Main(string[] args) { // 添加數(shù)據(jù)保護到服務(wù)中 var serviceCollection = new ServiceCollection(); serviceCollection.AddDataProtection(); var services = serviceCollection.BuildServiceProvider(); // 從DI中創(chuàng)建一個MyClass的實例 var instance = ActivatorUtilities.CreateInstance<MyClass>(services); instance.RunSample(); } public class MyClass { IDataProtector _protector; // 參數(shù) '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")中,參數(shù)“Contoso.MyClass.v1”可以理解為一個公鑰,因為 ASP.NET Core Data Protection 是非對稱加密(見前面介紹),所以系統(tǒng)中應(yīng)該還有一個密鑰,那么此處的密鑰 ASP.NET Core 在系統(tǒng)內(nèi)部幫你維護了。
讀到這里,有同學(xué)可能會問了,那系統(tǒng)中是如何幫我維護我的密鑰的呢? 我們不妨先來做一個測試。
首先,我在我的開發(fā)環(huán)境中,先把上面的程序中的解密部分代碼注釋掉,然后運行上面的程序,輸入一個“Hello World!” ,得到了一個加密的字符串CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ(略寫)。
然后我把同樣的程序拷貝到另外一臺開發(fā)環(huán)境的機器上,然后把上面的加密部分代碼注釋掉,使用第一步生成的CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ來解密,注意這兩步中我們都使用 "Contoso.MyClass.v1" 來做為公鑰。
運行程序,查看結(jié)果:
程序拋出了一個“System.Security.Cryptography.CryptographicException”異常的結(jié)果。
為什么呢? 這是因為每一臺機器都有一個自有的私鑰,由于在解密的過程中,這個私鑰是不同的,所以解密失敗,拋出了一個異常。
私鑰
私鑰存放在哪里呢?
1、如果程序寄宿在 Microsoft Azure下,存儲在“%HOME%\ASP.NET\DataProtection-Keys” 文件夾。
2、如果程序寄宿在IIS下,它被保存在HKLM注冊表的ACLed特殊注冊表鍵,并且只有工作進程可以訪問,它使用windows的DPAPI加密。
3、如果當(dāng)前用戶可用,即win10或者win7中,它存儲在“%LOCALAPPDATA%\ASP.NET\DataProtection-Keys”文件夾,同樣使用的windows的DPAPI加密。
4、如果這些都不符合,那么也就是私鑰是沒有被持久化的,也就是說當(dāng)進程關(guān)閉的時候,生成的私鑰就丟失了。
下面是博主機器上的私鑰文件:
一個xml配置文件,位于C:\Users\用戶名\AppData\Local\ASP.NET\DataProtection-Keys文件夾,名為:key-c37e3ed9-fbb5-47bc-9e8c-128afaf1c6d9.xml,內(nèi)容如下:
<?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>
文件包含一個創(chuàng)建日期,一個過期日期。間隔為90天,當(dāng)90天之后密鑰就會失效,系統(tǒng)將自動生成一個新的密鑰并設(shè)置新的密鑰作為活動的密鑰。只要已過期的密鑰還存在于系統(tǒng)上,你仍然可以解密任何受保護的數(shù)據(jù)。
文章不宜太長,下篇再接著寫。
總結(jié)
這篇文章算是對ASP.NET Core Data Protection做了一個大致的介紹,并且包含了一個簡單的使用方法。 在實際使用過程中,其實很多組件內(nèi)部都會使用到它,比如Session中間件,Identity中間件,Authercation中間件等等,對于普通開發(fā)人員在編碼的時候可能不會用到,但是在做系統(tǒng)分布式部署的時候如果你不了解這個機制可能就會遇到麻煩了(詳見蟋蟀博客的這篇文章),所以還是可以期待一下下文,更加深入的了解它,掌握它。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
讓GridView只更新某些特定的數(shù)據(jù)的方法
我又不希望所有的數(shù)據(jù)都可以修改,只希望修改某些特定的列,用下面的方法即可2008-10-10利用ASP.NET MVC+Bootstrap搭建個人博客之praise.js點贊特效插件(二)
這篇文章主要介紹了利用ASP.NET和MVC+Bootstrap搭建個人博客之praise.js點贊特效插件(二)的相關(guān)資料,需要的朋友可以參考下2016-06-06C#默認(rèn)以管理員身份運行程序?qū)崿F(xiàn)代碼
權(quán)限不夠,導(dǎo)致無法修改系統(tǒng)時間,于是我以管理員身份運行了一次,結(jié)果測試成功,下面為大家介紹下C#如何默認(rèn)以管理員身份運行程序2014-03-03Ajax實現(xiàn)異步刷新驗證用戶名是否已存在的具體方法
由于要做一個注冊頁面,看到許多網(wǎng)站上都是使用Ajax異步刷新驗證用戶名是否可用的,所以自己也動手做一個小實例2014-02-02c# 在WebBrowser中用SendMessage模擬鼠標(biāo)點擊
想在WebBrowser控件里面模擬鼠標(biāo)點擊,在百度上找了半天,怎么也找不到,還是google強大,在一個國外網(wǎng)站上找到的,代碼比較清楚了,不做說明。2010-02-02