ASP.NET Core中的資料保護

碼農譯站發表於2021-01-15

在這篇文章中,我將介紹ASP.NET Core 資料保護系統:它是什麼,為什麼我們需要它,以及它如何工作。

為什麼我們需要資料保護系統?

資料保護系統是ASP.NET Core使用的一組加密api。加密必須由不受信任的第三方處理的資料。

這方面的典型例子是身份驗證cookie。cookie是在請求之間持久化狀態的一種方法。你不希望每次向伺服器請求時都必須提供使用者名稱和密碼,這將非常麻煩!

相反,只需向伺服器提供一次憑據。伺服器驗證你的詳細資訊,併發出一個cookie,表明“他不需要提供任何其他證明,相信他。”對於後續的請求,可以簡單地提供該cookie,而不必提供憑據。瀏覽器自動傳送cookie與後續請求,這是web為使用者實現流暢登入體驗的方式。

cookie是非常敏感的東西。任何包含cookie的請求都將被視為原始使用者傳送的請求,就像原始使用者在每個請求中都提供了使用者名稱和密碼一樣。瀏覽器中有很多保護措施(例如CORS)來阻止攻擊者訪問這些cookie。

然而,這不僅僅是阻止別人得到你的cookie。作為一個網站所有者,你也不希望使用者篡改他們自己的cookie。

身份驗證cookie通常不僅僅包含經過身份驗證的使用者的ID或名稱。它們通常包含各種附加的要求。它包含了使用者的詳細資訊。它們可以是真實資料,如名稱、電子郵件或電話號碼,但它們也可以是與許可權相關的宣告,如是否是管理員或是否可以編輯。

對於每個請求,通常都需要這些,以確定是否允許使用者採取操作。通常包含在傳送給使用者的身份驗證cookie中,而不是每次請求都必須從資料庫載入。

這使得應用程式更加容易——一旦通過從cookie中提取使用者主體對使用者進行身份驗證,應用程式就會確切地知道使用者擁有哪些許可權。這意味著應用程式必須信任cookie。如果cookie是明文傳送的,那麼使用者只需編輯這些值,就會暴露應用程式中明顯的安全漏洞。

ASP.NET Core資料保護系統正是為了這個目的而使用的。它對敏感資料(如身份驗證cookie)進行加密和解密。通過在響應中返回身份驗證cookie之前對其進行加密,應用程式知道該cookie沒有被篡改,並可以信任其值。

資料保護系統如何工作?

資料保護系統試圖解決一個棘手的問題:如何保護暴露給攻擊者的敏感資料,理想情況下不向開發人員暴露任何金鑰,同時遵循加密的最佳實踐。

資料保護系統使用對稱金鑰加密來保護資料。使用包含隨機資料的金鑰加密資料,使用相同的金鑰解密資料。

在一個典型的ASP.NET Core應用程式可能有幾種不同型別的不相關資料需要加密。例如,除了身份驗證cookie之外,可能還需要加密跨站點請求偽造令牌(CSRF)或密碼重置令牌。

你可以將相同的鍵用於所有這些不同的目的,但這可能會帶來問題。例如,如果密碼重置令牌不能“意外地”(更有可能是惡意地)用作身份驗證令牌,那就好得多。

ASP.NET Core資料保護系統實現了這一目標。資料保護系統有一個不能直接使用的父金鑰。必須從父金鑰派生子金鑰,這些子金鑰用於加密和解密資料。

使用相同的purpose字串從父金鑰派生金鑰總是會給出相同的金鑰,因此如果你擁有父金鑰並且知道purpose字串,那麼總是可以解密已加密的資料。如果金鑰是用不同的purpose匯出的,那麼嘗試解密資料將會失敗。這樣可以保持資料隔離,這對安全性更好。

在大多數情況下,你不必直接與資料保護系統互動來建立金鑰或加密資料。這是由ASP.NET Core核心框架及其附帶的庫處理的。它們確保在你的應用程式中為每個不同的purpose使用唯一的字串。如果你願意,你可以建立自己的保護程式並加密其他資料(見下文),但這不是ASP.NET Core的日常執行所必需的。

我是一個.net框架開發者——這聽起來很像<machineKey>?

資料保護系統是ASP.NET Core的一個新功能。,但是保護身份驗證令牌的需要並不是新的,那麼我們以前用的是什麼呢?答案是<machineKey>。<machineKey>元素的使用方式與ASP.NET Core資料保護系統非常相似,配置金鑰和密碼學套件,用於通過身份驗證系統加密資料(以及其他地方)。不幸的是,使用這個金鑰時有些複雜,因為它通常是從machine.config讀取的。必須在執行應用程式的機器上配置。在叢集中執行時,必須確保這些鍵保持同步,否則可能會產生問題!

在.net Framework 4.5中,我們可以替換<machineKey>元素及其使用的整個加密管道。

如何管理資料保護金鑰?

如果對安全性有所瞭解,那麼你可能已經聽到應該定期輪換密碼、機密和證書的說法。如果你的某個祕密被洩露了,這可以在一定程度上減少影響。這就是為什麼簽發HTTPS證書的壽命越來越短的原因。

根據你從框架和工具獲得的支援,更換祕鑰和證書可能會很痛苦,特別是在過渡時期,可能需要同時支援新舊祕鑰。

鑑於資料保護對於保護ASP.NET Core是至關重要的。你不會驚訝祕鑰輪換是資料保護系統的預設設定。預設情況下,資料保護的生命週期為90天,但通常不必為此擔心。當舊金鑰快要過期時,資料保護系統會自動建立新的金鑰。所有可用金鑰的集合稱為密匙環。

在這篇文章中,我不會深入金鑰管理的細節。請注意,祕鑰輪換是自動發生的,只要你不刪除任何舊的鍵(或顯式地撤銷它們),那麼加密的資料仍然可以使用過期的鍵檢索。過期的金鑰不能用於加密新資料。

我是否也可以保護其他資料,還是僅用於身份驗證cookie?

資料保護系統由ASP.NET Core隱含地使用並處理認證令牌的加密和解密。它也被ASP.NET Core用來保護密碼重置和MFA令牌。你不需要為這種保護做任何事情——框架自己處理保護。

如果你有自己想要加密的臨時資料,可以直接使用資料保護api。我將在後面的文章中詳細介紹,但以下內容展示了中如何使用IDataProtectionProvider服務(預設在ASP.NET Core apps)加密和解密一些資料:

public class MyClass
{
    // The IDataProtectionProvider is registered by default in ASP.NET Core
    readonly IDataProtectionProvider _rootProvider;
    public MyClass(IDataProtectionProvider rootProvider)
    {
        _rootProvider = rootProvider;
    }

    public void RunSample()
    {
        // Create a child key using the purpose string
        string purpose = "Contoso.MyClass.v1";
        IDataProtector protector = provider.CreateProtector(purpose);

        // Get the data to protect
        Console.Write("Enter input: ");
        string input = Console.ReadLine();
        // Enter input: Hello world!

        // protect the payload
        string protectedPayload = _protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");
        //PRINTS: Protect returned: CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ

        // unprotect the payload
        string unprotectedPayload = _protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
        //PRINTS: Unprotect returned: Hello world
    }
}

一般來說,這並不是你想要做的事情。我個人只在處理密碼重置和類似的令牌時需要它。

有什麼是我不應該使用資料保護的嗎?

重要的一點是,資料保護系統並不是真正用於通用加密。我們希望你加密的東西,就其本質而言,有一個有限的生命週期,如身份驗證令牌和密碼重置令牌。

理論上,你可以對希望加密和長期儲存的資料(例如在資料庫中)使用資料保護系統。資料保護金鑰每90天過期一次(預設情況下),但是你仍然可以使用過期的金鑰解密資料。

如果資料保護金鑰因為某種原因被刪除,真正的危險就來了。不建議這樣做,但意外總是會發生的。如果使用正確,刪除資料保護金鑰對大多數應用程式的影響相對較小——使用者將不得不再次登入,以前發出的密碼重置鍵將無效——這很煩人,但不會造成災難。

另一方面,如果你已經用資料保護系統加密了敏感資料,然後將其儲存在資料庫中,那麼就有大問題了。那些資料都不見了,被毀了。絕對不值得冒這個險!相反,你應該使用.NET Core中的專用加密庫,以及為此目的建立的特定證書或金鑰。

如何在我的ASP.NET Core中配置資料保護?

通常,你與資料保護系統互動的唯一地方是配置它的時候,如果沒有正確地配置它,你可能會暴露於安全漏洞中,或者無法解密身份驗證cookie。

一方面,資料保護系統需要易於配置和維護,因為複雜性和維護開銷通常會導致bug或不良實踐。但ASP.NET Core還需要在各種環境下執行:Windows、Linux、macOS;在Azure, AWS;在高階伺服器和樹莓派上。每個平臺都有不同的內建加密機制和可用特性,而.NET Core需要在所有這些平臺上都是安全的。

為了解決這個問題,資料保護系統使用了一種通用的“外掛”式架構。基本上有兩個不同的可插入區域:

  1. 金鑰環永續性位置:金鑰應該儲存在哪裡?
  2. 永續性加密:金鑰是否應該在靜止時加密,如果是,如何加密。

ASP.NET Core試圖在預設情況下將這些設定為合理的選項。例如,在Windows(非azure應用程式)機器上,將持久化到%LOCALAPPDATA%\ASP.net\資料加密金鑰。

不幸的是,一旦你開始在生產環境中執行應用程式並對應用程式進行擴充套件,大多數預設設定都將不起作用。相反,你可能需要研究一種可選的配置方法。

總結

在這篇文章中,我提供了ASP.NET Core資料保護系統的高階概述。我描述了資料保護系統的動機以及它背後的一些設計原則。

歡迎關注我的公眾號,如果你有喜歡的外文技術文章,可以通過公眾號留言推薦給我。

相關文章