ASP.NET Core 數據保護(Data Protection)【上】

前言

上一篇博客記錄瞭如何在 Kestrel 中使用 HTTPS(SSL), 也是咱們目前項目中實際使用到的。html

數據安全每每是開發人員很容易忽略的一個部分,包括我本身。近兩年業內也出現了不少由於安全問題致使了不少嚴重事情發生,因此安全對咱們開發人員很重要,咱們要對咱們的代碼的安全負責。web

在工做中,咱們經常會見到 encode,base64,sha256, rsa, hash,encryption, md5 等,一些人對他們還傻傻分不清楚,也不知道何時使用他們,還有一些人認爲MD5就是加密算法。算法

在 ASP.NET Core 中,爲數據保護相關提供了一批新的 API,包括加密解密機制,下面就讓咱們來看看吧。windows

目錄

  • 加密,編碼,哈希之間的區別
  • 數據保護(Data Protection)介紹
  • ASP.NET Core 中的數據保護
  • 總結

編碼,加密,哈希之間的區別

編碼
編碼是信息從一種形式或格式轉換爲另外一種形式的過程,他們是可逆的。
如 url、base6四、jsunicode、utf-8等等。api

加密
加密是可逆的,相似於編碼也是把數據從一種形式轉換爲另外一種形式,它經過一個特定的加密的密匙,相對應的有解密的過程。加解密的算法有2種:對稱加密算法和非對稱加密算法。
對稱:DES、AES、SM一、RC4 等等。
非對稱:RSA、ECC、SM2 等等。安全

哈希
又叫"散列",就是把任意長度的數據轉換成固定長度的「指紋」,這個過程是不可逆的。並且只要輸入發生改變,輸出的 hash值也會有很大不一樣。
它還有一個特性是相同的輸入老是有相同的結果, 這種特性剛好合適用來用來保存密碼。
如:MD五、SHA256, SHA512, RipeMD, WHIRLPOOL等等。服務器

數據保護(Data Protection)介紹

在看數據保護官方文檔的時候,微軟的文檔是這樣寫的,大體意思就是他們基於幾點需求,要開發一套數據保護的庫以便用來給受信任的客戶端和不受信任的客戶端來使用。這幾點要求就是:cookie

一、真實性、完整性
舉了一個身份驗證cookie的例子,就是服務端生成了一個包含xyz權限的token,而後會在未來的某個時間過時,這個時候就須要從新請求生成一個,怎麼樣來保證請求的token不是被篡改過的。session

二、機密性
服務器要保證請求是受信任的,因此就須要一些包含特定操做環境的信息,好比一個路徑,一個權限或者一個句柄或者其餘的一些東西特定於服務器的東西,這些信息不該該透漏給不受信任的客戶端,也就是說相似於私鑰。框架

三、隔離性
而後就是要求作成一個組件,而且這個組件具備獨立性,能夠不依賴於系統中的其餘組件。如一個bearer token的組件,它要使用這個組件的話,也不須要引用anti-CSRF這種機制了。

再進一步的縮小需求範圍,加密的數據不須要在系統以外的其餘系統中使用,另外處理速度要儘量的快,由於每一次web請求都會使用加密組件一次或者屢次。

基於以上要求,微軟提出來可使用密碼學,由於這是一個典型的密碼學應用的場景。確實這是一個密碼學的應用場景,而且是一個非對稱加密算法的場景。可是你們都知道,非對稱加密是由一個公鑰和私鑰用來保證安全性的,即便公鑰遭泄露,整個通信仍然是安全的,這就是它比對稱加密的好處。可是非對稱加密也是有缺點的,就是加密和解密花費的時間長,速度慢。

可是上面的要求又是須要速度儘量快,怎麼辦呢? 因而微軟的工程師們想出了能夠經過精簡而且優化非對稱加密機制,來達到這個要求。由於不須要跨系統或者跨語言什麼的,因此也不須要什麼協議之類的,這就給優化帶來了更多的可能性。

到這裏,我就想,若是讓我來基於以上幾點來設計開發這樣一個系統,我應該怎麼樣設計?怎麼樣達到要求?
帶着這個問題,咱們來進一步看看微軟是怎麼樣作的吧?

下面是一些總結的設計原則 :

一、配置應該儘可能的簡單,默認狀況下應該能夠零配置,開發人員能夠直接運行。

二、提供一個簡單的API,應該容易使用,而且不會輕易用錯。

三、開發人員不須要專門學習怎麼樣管理這些鑰(公鑰,私鑰),系統應該自動的選擇算法和管理鑰的生命週期。理想狀況下開發人員都不該該訪問這些鑰的原始文件。

四、鑰應該是受保護的,不會被遠程調用到。系統應該有一個自動保護機制而且能夠自動應用。

若是讓我設計這樣一個庫,我可能不會想到這麼多,也許只會想到前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" 來作爲公鑰。

運行程序,查看結果:
image

程序拋出了一個「System.Security.Cryptography.CryptographicException」異常的結果。

爲何呢? 這是由於每一臺機器都有一個自有的私鑰,因爲在解密的過程當中,這個私鑰是不一樣的,因此解密失敗,拋出了一個異常。

私鑰

私鑰存放在哪裏呢?

一、若是程序寄宿在 Microsoft Azure下,存儲在「%HOME%\ASP.NET\DataProtection-Keys」 文件夾。

二、若是程序寄宿在IIS下,它被保存在HKLM註冊表的ACLed特殊註冊表鍵,而且只有工做進程能夠訪問,它使用windows的DPAPI加密。

三、若是當前用戶可用,即win10或者win7中,它存儲在「%LOCALAPPDATA%\ASP.NET\DataProtection-Keys」文件夾,一樣使用的windows的DPAPI加密。

四、若是這些都不符合,那麼也就是私鑰是沒有被持久化的,也就是說當進程關閉的時候,生成的私鑰就丟失了。

下面是博主機器上的私鑰文件:

一個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中間件等等,對於普通開發人員在編碼的時候可能不會用到,可是在作系統分佈式部署的時候若是你不瞭解這個機制可能就會遇到麻煩了(詳見蟋蟀博客的這篇文章),因此仍是能夠期待一下下文,更加深刻的瞭解它,掌握它。


本文地址:http://www.cnblogs.com/savorboard/p/dotnetcore-data-protection.html
做者博客:Savorboard 歡迎轉載,請在明顯位置給出出處及連接

相關文章
相關標籤/搜索