Ciągi przeznaczenia w ASP.NET Core
Składniki, które używają IDataProtectionProvider
, muszą przekazać unikatowy parametr celów do CreateProtector
metody . Parametr purposes jest nieodłączną częścią zabezpieczeń systemu ochrony danych, ponieważ zapewnia izolację między użytkownikami kryptograficznymi, nawet jeśli główne klucze kryptograficzne są takie same.
Gdy użytkownik określa cel, ciąg przeznaczenia jest używany wraz z głównymi kluczami kryptograficznymi w celu uzyskania podklucze kryptograficzne unikatowe dla tego konsumenta. To izoluje użytkownika od wszystkich innych odbiorców kryptograficznych w aplikacji: żaden inny składnik nie może odczytać ładunków i nie może odczytać żadnych ładunków innych składników. Ta izolacja renderuje również niewykonalne całe kategorie ataków na składnik.
Na powyższym IDataProtector
diagramie wystąpienia A i B nie mogą odczytywać ładunków siebie, tylko ich własnych.
Ciąg przeznaczenia nie musi być tajny. Powinien być po prostu unikatowy w tym sensie, że żaden inny dobrze zachowywany składnik nigdy nie będzie dostarczać tego samego ciągu przeznaczenia.
Napiwek
Używanie przestrzeni nazw i nazwy typu składnika korzystającego z interfejsów API ochrony danych jest dobrą regułą, ponieważ w praktyce te informacje nigdy nie będą powodować konfliktów.
Składnik utworzony przez firmę Contoso, który jest odpowiedzialny za wybicie tokenów elementu nośnego, może używać nazwy Contoso.Security.BearerToken jako ciągu przeznaczenia. Lub — jeszcze lepiej — może użyć nazwy Contoso.Security.BearerToken.v1 jako ciągu przeznaczenia. Dołączanie numeru wersji umożliwia przyszłej wersji używanie nazwy Contoso.Security.BearerToken.v2, a różne wersje będą całkowicie odizolowane od siebie, jeśli chodzi o ładunki.
Ponieważ parametr purposes to CreateProtector
tablica ciągów, powyższe zamiast tego można określić jako [ "Contoso.Security.BearerToken", "v1" ]
. Umożliwia to ustanowienie hierarchii celów i otwarcie możliwości obsługi wielu dzierżaw w systemie ochrony danych.
Ostrzeżenie
Składniki nie powinny zezwalać na wprowadzanie niezaufanych danych wejściowych użytkownika jako jedyne źródło danych wejściowych dla łańcucha celów.
Rozważmy na przykład składnik Contoso.Messaging.SecureMessage, który jest odpowiedzialny za przechowywanie bezpiecznych komunikatów. Jeśli składnik bezpiecznego przesyłania komunikatów miał wywołać CreateProtector([ username ])
metodę , złośliwy użytkownik może utworzyć konto z nazwą użytkownika "Contoso.Security.BearerToken" w celu wywołania składnika CreateProtector([ "Contoso.Security.BearerToken" ])
, co powoduje niezamierzone spowodowanie niezamierzonego wywołania bezpiecznego systemu obsługi komunikatów w celu wypęcenia ładunków, które mogą być postrzegane jako tokeny uwierzytelniania.
Lepszym łańcuchem celów dla składnika obsługi komunikatów jest CreateProtector([ "Contoso.Messaging.SecureMessage", $"User: {username}" ])
, który zapewnia właściwą izolację.
Izolacja zapewniana przez i zachowania IDataProtectionProvider
elementów , IDataProtector
i jest następująca:
Dla danego
IDataProtectionProvider
obiektu metoda utworzyIDataProtector
obiekt jednoznacznie powiązany zarówno z obiektemIDataProtectionProvider
, który go utworzył, jak i parametrem purposes, który zostałCreateProtector
przekazany do metody.Parametr purpose nie może mieć wartości null. (Jeśli cele są określone jako tablica, oznacza to, że tablica nie może mieć zerowej długości, a wszystkie elementy tablicy muszą mieć wartość inną niż null). Pusty cel ciągu jest technicznie dozwolony, ale jest odradzany.
Dwa argumenty celów są równoważne, jeśli i tylko wtedy, gdy zawierają te same ciągi (przy użyciu porównania porządkowego) w tej samej kolejności. Pojedynczy argument przeznaczenia jest odpowiednikiem tablicy celów pojedynczego elementu.
Dwa
IDataProtector
obiekty są równoważne, jeśli i tylko wtedy, gdy są tworzone na podstawie równoważnychIDataProtectionProvider
obiektów z równoważnymi parametrami celów.W przypadku danego
IDataProtector
obiektu wywołanieUnprotect(protectedData)
metody zwróci oryginałunprotectedData
, jeśli i tylko wtedy, gdyprotectedData := Protect(unprotectedData)
dla równoważnegoIDataProtector
obiektu.
Uwaga
Nie rozważamy przypadku, w którym jakiś składnik celowo wybiera ciąg przeznaczenia, który jest znany jako konflikt z innym składnikiem. Taki składnik zasadniczo byłby uważany za złośliwy, a ten system nie ma na celu zapewnienia gwarancji bezpieczeństwa w przypadku, gdy złośliwy kod jest już uruchomiony wewnątrz procesu roboczego.