ASP.NET Core'da anahtarları iptal edilen yüklerin korumasını kaldırma
ASP.NET Core veri koruma API'leri öncelikli olarak gizli yüklerin süresiz kalıcılığına yönelik değildir. Windows CNG DPAPI ve Azure Rights Management gibi diğer teknolojiler, süresiz depolama senaryosuna daha uygundur ve buna karşılık güçlü anahtar yönetimi özelliklerine sahiptir. Buna göre, bir geliştiricinin gizli verilerin uzun süreli korunması için ASP.NET Core veri koruma API'lerini kullanmasını yasaklayan hiçbir şey yoktur. Anahtarlar hiçbir zaman anahtar halkasından kaldırılmaz, bu nedenle IDataProtector.Unprotect
anahtarlar kullanılabilir ve geçerli olduğu sürece mevcut yükleri her zaman kurtarabilir.
Ancak geliştirici, iptal edilmiş bir anahtarla korunan verilerin korumasını kaldırmaya çalıştığında ve bu durumda bir özel durum oluşturacağı için IDataProtector.Unprotect
bir sorun ortaya çıkar. Bu tür yükler sistem tarafından kolayca yeniden oluşturulabileceğinden ve en kötü durumda site ziyaretçisinin yeniden oturum açması gerekebileceğinden, kısa süreli veya geçici yüklerde (kimlik doğrulama belirteçleri gibi) bu sorun olmayabilir. Ancak kalıcı yüklerin atılmış olması Unprotect
kabul edilemez veri kaybına yol açabilir.
IPersistedDataProtector
İptal edilen anahtarlar karşısında bile yüklerin korumasız olmasına izin verme senaryolarını desteklemek için veri koruma sistemi bir IPersistedDataProtector
tür içerir. örneğini IPersistedDataProtector
almak için örneğini normal bir şekilde almanız IDataProtector
ve öğesini olarak atamayı denemeniz IDataProtector
yeterlidir IPersistedDataProtector
.
Not
Tüm IDataProtector
örnekler'e IPersistedDataProtector
yayınlanamaz. Geliştiriciler geçersiz atamaların neden olduğu çalışma zamanı özel durumlarını önlemek için C# işlecini veya benzerini kullanmalıdır ve hata durumunu uygun şekilde işlemeye hazır olmalıdır.
IPersistedDataProtector
aşağıdaki API yüzeyini kullanıma sunar:
DangerousUnprotect(byte[] protectedData, bool ignoreRevocationErrors,
out bool requiresMigration, out bool wasRevoked) : byte[]
Bu API korumalı yükü (bayt dizisi olarak) alır ve korumasız yükü döndürür. Dize tabanlı aşırı yükleme yoktur. İki out parametresi aşağıdaki gibidir.
requiresMigration
: Bu yükü korumak için kullanılan anahtar artık etkin varsayılan anahtar değilse olarak ayarlanırtrue
. Örneğin, bu yükü korumak için kullanılan anahtar eskidir ve anahtar döndürme işlemi o zamandan beri gerçekleştirilir. Arayan, iş gereksinimlerine bağlı olarak yükü yeniden korumayı düşünebilir.wasRevoked
: Bu yükü korumak için kullanılan anahtarın iptal edilmiş olup olmadığını olarak ayarlanırtrue
.
Uyarı
yöntemine DangerousUnprotect
geçerken ignoreRevocationErrors: true
çok dikkatli olun. Bu yöntem wasRevoked
çağrıldıktan sonra değer true ise, bu yükü korumak için kullanılan anahtar iptal edilir ve yükün orijinalliği şüpheli olarak ele alınmalıdır. Bu durumda, korumasız yük üzerinde çalışmaya devam edin; örneğin, güvenilir olmayan bir web istemcisi tarafından gönderilmek yerine güvenli bir veritabanından geldiği gibi, bunun doğru olduğuna dair ayrı bir güvenceniz varsa.
using System;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.DependencyInjection;
public class Program
{
public static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection()
// point at a specific folder and use DPAPI to encrypt keys
.PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
.ProtectKeysWithDpapi();
var services = serviceCollection.BuildServiceProvider();
// get a protector and perform a protect operation
var protector = services.GetDataProtector("Sample.DangerousUnprotect");
Console.Write("Input: ");
byte[] input = Encoding.UTF8.GetBytes(Console.ReadLine());
var protectedData = protector.Protect(input);
Console.WriteLine($"Protected payload: {Convert.ToBase64String(protectedData)}");
// demonstrate that the payload round-trips properly
var roundTripped = protector.Unprotect(protectedData);
Console.WriteLine($"Round-tripped payload: {Encoding.UTF8.GetString(roundTripped)}");
// get a reference to the key manager and revoke all keys in the key ring
var keyManager = services.GetService<IKeyManager>();
Console.WriteLine("Revoking all keys in the key ring...");
keyManager.RevokeAllKeys(DateTimeOffset.Now, "Sample revocation.");
// try calling Protect - this should throw
Console.WriteLine("Calling Unprotect...");
try
{
var unprotectedPayload = protector.Unprotect(protectedData);
Console.WriteLine($"Unprotected payload: {Encoding.UTF8.GetString(unprotectedPayload)}");
}
catch (Exception ex)
{
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
// try calling DangerousUnprotect
Console.WriteLine("Calling DangerousUnprotect...");
try
{
IPersistedDataProtector persistedProtector = protector as IPersistedDataProtector;
if (persistedProtector == null)
{
throw new Exception("Can't call DangerousUnprotect.");
}
bool requiresMigration, wasRevoked;
var unprotectedPayload = persistedProtector.DangerousUnprotect(
protectedData: protectedData,
ignoreRevocationErrors: true,
requiresMigration: out requiresMigration,
wasRevoked: out wasRevoked);
Console.WriteLine($"Unprotected payload: {Encoding.UTF8.GetString(unprotectedPayload)}");
Console.WriteLine($"Requires migration = {requiresMigration}, was revoked = {wasRevoked}");
}
catch (Exception ex)
{
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
}
}
/*
* SAMPLE OUTPUT
*
* Input: Hello!
* Protected payload: CfDJ8LHIzUCX1ZVBn2BZ...
* Round-tripped payload: Hello!
* Revoking all keys in the key ring...
* Calling Unprotect...
* CryptographicException: The key {...} has been revoked.
* Calling DangerousUnprotect...
* Unprotected payload: Hello!
* Requires migration = True, was revoked = True
*/
ASP.NET Core