demoshop

demo, trying to be the best_

在 .NET Core後微軟為了讓開發人員更輕鬆簡單的使用資料保護API,並且作為ASP.NET 1.x - 4.x 中 <machineKey> 元素的長期替代品。 解決舊密碼編譯堆疊的許多缺點,同時為現代應用程式可能遇到的大部分使用案例提供現成的解決方案。

設計理念

  • 無須特別設定:系統應該提供簡單的設定。 在理想情況下,系統會是零設定,而開發人員可以立即快馬加鞭地開展工作。 在開發人員需要設定特定層面 (例如金鑰存放庫) 的情況下,應考慮讓這些特定設定變得簡單。
  • 簡單易用:提供簡單的取用者面向 API。 API 應該很容易正確使用,而且難以不正確地使用。
  • 降低使用門檻:開發人員應該不需要學習金鑰管理原則。 系統應該代表開發人員處理演算法選取和金鑰存留期。 在理想情況下,開發人員甚至不應該擁有原始金鑰資料的存取權。
  • 金鑰自動保護:金鑰應盡可能在待用時受到保護。 系統應該找出適當的預設保護機制,並自動套用該機制。

考慮到這些原則,微軟開發了一個簡單、便於使用的資料保護堆疊。開發者只需要認識IDataProtectorIDataProtectionProvider兩個介面,加解密也只有兩個方法ProtectUnprotect就可以完成絕大部分的資料保護處理,馬上來感受它的威力。

在ASP.NET Core 8中已經不需要注入 builder.Services.AddDataProtection就可以直接使用了

威力展示-資料保護

開啟MVC, RazorPages, SignalR 任一專案都可以使用(本範例使用RazorPages)

直接調整 Index 如下:

public class IndexModel : PageModel
{
    private readonly IDataProtector _dataProtector;
    public IndexModel(IDataProtectionProvider dataProtector)
    {
        _dataProtector = dataProtector.CreateProtector("SkillTree");
    }

    public string ProtectValue { get; set; }
    public void OnGet()
    {
        ProtectValue = _dataProtector.Protect("SkillTree.my");
    }
}
  1. 建立IDataProtector欄位
  2. 使用DI的建構子注入 IDataProtectionProvider
  3. 建立資料保護(你可以把 SkillTree這個字串直接當公鑰來想)
  4. 保護資料(範例保護的字串是SkillTree.my
  5. 完工

調整頁面,看看保護後的密文

@page
@model IndexModel
<div class="text-center">
    <textarea>@Model.ProtectValue</textarea>
</div>

這樣子網頁一執行就會直接秀出密文

解除資料保護

為了後續的範例方便,所以我特別建立了新的頁面名稱取為UnProtect程式如下:

public class UnProtectModel : PageModel
{
    private readonly IDataProtector _protector;

    public UnProtectModel(IDataProtectionProvider protector)
    {
        _protector = protector.CreateProtector("SkillTree");

    }
    [BindProperty]
    public string ProtectValue { get; set; }

    public string UnProtectValue { get; set; }
    
    public void OnGet()
    {
    }

    public void OnPost()
    {
        UnProtectValue= _protector.Unprotect(ProtectValue);
    }
}

頁面調整

@page
@model DataProtector_SkillTree.Pages.UnProtectModel
<div class="text-center">
    <h1 class="display-4">解密值:「@Model.UnProtectValue」</h1>
    <form method="post">
        <input asp-for="ProtectValue"/>
        <button type="submit">解密</button>
    </form>
</div>

建立完成後,只要把首頁顯示的密文全選複製,貼到UnProtect頁面按下「解密」就可以看到解除保護的值了

加上時間限制

如果需要更嚴苛的保護,還可以加上時戳。

有時間限制的資料保護

public class IndexModel : PageModel
{
    private readonly IDataProtector _dataProtector;

    public IndexModel(IDataProtectionProvider dataProtector)
    {
        _dataProtector = dataProtector.CreateProtector("SkillTree");
    }

    public string ProtectValue { get; set; }

    public void OnGet()
    {
        var timeLimitedDataProtector = _dataProtector.ToTimeLimitedDataProtector();
        ProtectValue = timeLimitedDataProtector.Protect("SkillTree.my",
                                                        lifetime: new TimeSpan(0, 0, 5));
        //ProtectValue = _dataProtector.Protect("SkillTree.my");
    }
}

這樣子密文在五秒內沒解除保護就會失效,非常嚴謹!不過如果使用了時間限制,解除保護的程式也記得要調整

有時間限制的解除資料保護

public class UnProtectModel : PageModel
{
    private readonly IDataProtector _protector;

    public UnProtectModel(IDataProtectionProvider protector)
    {
        _protector = protector.CreateProtector("SkillTree");

    }

    [BindProperty] public string ProtectValue { get; set; }

    public string UnProtectValue { get; set; }

    public void OnGet()
    {
    }

    public void OnPost()
    {
        var timeLimitedDataProtector = _protector.ToTimeLimitedDataProtector();
        UnProtectValue = timeLimitedDataProtector.Unprotect(ProtectValue);
        //UnProtectValue = _protector.Unprotect(ProtectValue);
    }
}

結論

就這樣非常簡單的資料保護API就完成了非對稱加密的需求,公鑰就是我們自行設定的SkillTree那私鑰勒?開發人員根本不用知道在Window會放在%LOCALAPPDATA%\ASP.NET\DataProtection-KeysLinux存在$HOME/.aspnet/DataProtection-Keys而Mac則是$HOME/.aspnet/DataProtection-KeysAPI都幫我們搞定了連預設是90天會換一次私鑰都和我們沒關係,所以非常推薦各位開發者使用這套全新的資料保護API

系列文章

回應討論