Usiłuję zrozumieć cel SecureString .NET. Z MSDN:
Instancja klasy System.String jest zarówno niezmienna, jak i gdy nie jest już potrzebna, nie może być programowo zaplanowana do odśmiecania; oznacza to, że wystąpienie jest tylko do odczytu po utworzeniu i nie można przewidzieć, kiedy wystąpienie zostanie usunięte z pamięci komputera. W konsekwencji, jeśli obiekt String zawiera poufne informacje, takie jak hasło, numer karty kredytowej lub dane osobowe, istnieje ryzyko, że informacje mogą zostać ujawnione po ich użyciu, ponieważ aplikacja nie może usunąć danych z pamięci komputera.
Obiekt SecureString jest podobny do obiektu String, ponieważ ma wartość tekstową. Jednak wartość obiektu SecureString jest automatycznie szyfrowana, może być modyfikowana, dopóki aplikacja nie oznaczy go jako tylko do odczytu, i może zostać usunięta z pamięci komputera przez aplikację lub moduł czyszczenia pamięci .NET Framework.
Wartość wystąpienia SecureString jest automatycznie szyfrowana przy inicjowaniu wystąpienia lub po modyfikacji wartości. Twoja aplikacja może uczynić instancję niezmienną i zapobiec dalszej modyfikacji przez wywołanie metody MakeReadOnly.
Czy automatyczne szyfrowanie to duża wypłata?
I dlaczego nie mogę po prostu powiedzieć:
SecureString password = new SecureString("password");
zamiast
SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
pass.AppendChar(c);
Jakiego aspektu SecureString mi brakuje?
źródło
SecureString
nowego oprogramowania: github.com/dotnet/platform-compat/blob/master/docs/DE0001.mdOdpowiedzi:
Przestałbym używać SecureString. Wygląda na to, że chłopaki PG rezygnują z tego wsparcia. Być może nawet wyciągniesz go w przyszłości - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .
źródło
Niektóre części frameworka, które obecnie używają
SecureString
:System.Windows.Controls.PasswordBox
Kontrola WPF zachowuje hasło jako SecureString wewnętrznie (ujawniane jako kopia poprzezPasswordBox::SecurePassword
)System.Diagnostics.ProcessStartInfo::Password
Nieruchomość jestSecureString
X509Certificate2
przyjmujeSecureString
hasłoGłównym celem jest zmniejszenie powierzchni ataku, a nie jej wyeliminowanie.
SecureStrings
są „przypięte” do pamięci RAM, więc Garbage Collector nie będzie go przesuwał ani kopiował. Daje również pewność, że zwykły tekst nie zostanie zapisany w pliku wymiany lub w zrzutach pamięci. Szyfrowanie bardziej przypomina zaciemnianie i nie powstrzyma jednak określonego hakera, który byłby w stanie znaleźć klucz symetryczny użyty do jego zaszyfrowania i odszyfrowania.Jak powiedzieli inni, powodem, dla którego musisz stworzyć
SecureString
znak po znaku, jest pierwsza oczywista wada polegająca na zrobieniu czegoś innego: prawdopodobnie masz już tajną wartość jako zwykły ciąg znaków, więc o co chodzi?SecureString
s to pierwszy krok w rozwiązaniu problemu z kurczakiem i jajkiem, więc nawet jeśli większość obecnych scenariuszy wymaga przekształcenia ich z powrotem w regularne ciągi, aby w ogóle z nich skorzystać, ich istnienie w strukturze oznacza teraz lepsze wsparcie dla nich w przyszłość - przynajmniej do punktu, w którym twój program nie musi być słabym ogniwem.źródło
Edycja : Nie używaj SecureString
Obecne wytyczne mówią teraz, że klasa nie powinna być używana. Szczegóły można znaleźć pod tym linkiem: https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
Z artykułu:
DE0001: Nie należy używać SecureString
Motywacja
SecureString
jest uniknięcie przechowywania sekretów w pamięci procesu jako zwykłego tekstu.SecureString
nie istnieje jako koncepcja systemu operacyjnego.System.String
- czas życia natywnego bufora jest krótszy.Rekomendacje
Nie używaj
SecureString
do nowego kodu. Podczas przenoszenia kodu do .NET Core należy wziąć pod uwagę, że zawartość tablicy nie jest zaszyfrowana w pamięci.Ogólne podejście do obsługi poświadczeń polega na unikaniu ich i poleganiu na innych sposobach uwierzytelnienia, takich jak certyfikaty lub uwierzytelnianie systemu Windows.
Zakończ edycję: oryginalne podsumowanie poniżej
Wiele świetnych odpowiedzi; oto krótkie streszczenie tego, co zostało omówione.
Microsoft wdrożył klasę SecureString, aby zapewnić lepsze bezpieczeństwo poufnych informacji (takich jak karty kredytowe, hasła itp.). Automatycznie zapewnia:
Obecnie SecureString jest ograniczony w użyciu, ale oczekuje lepszej adaptacji w przyszłości.
W oparciu o te informacje konstruktor SecureString nie powinien po prostu pobierać ciągu i kroić go na tablicę znaków, ponieważ wypisanie ciągu nie spełnia celu funkcji SecureString.
Dodatkowe informacje:
Edycja: Trudno było wybrać najlepszą odpowiedź, ponieważ w wielu jest dobra informacja; szkoda, że nie ma opcji odpowiedzi wspomaganej.
źródło
Krótka odpowiedź
Ponieważ teraz masz
password
w pamięci; bez możliwości jego wyczyszczenia - właśnie o to chodzi w SecureString .Długa odpowiedź
Powodem SecureString istnieje dlatego, że nie można używać ZeroMemory wytrzeć poufnych danych, gdy jesteś z nim zrobić. Istnieje on do rozwiązania problemu, który istnieje , ponieważ CLR.
W zwykłej natywnej aplikacji dzwoniłbyś
SecureZeroMemory
:Uwaga : SecureZeroMemory jest identyczny
ZeroMemory
, z wyjątkiem tego , że kompilator go nie zoptymalizuje.Problem polega na tym, że nie można dzwonić
ZeroMemory
ani korzystać zSecureZeroMemory
platformy .NET. A w .NET ciągi są niezmienne; nie możesz nawet zastąpić zawartości ciągu, jak w innych językach:Więc co możesz zrobić? W jaki sposób zapewniamy w .NET możliwość czyszczenia hasła lub numeru karty kredytowej z pamięci, gdy skończymy z tym?
Jedynym sposobem, w jaki można to zrobić, byłoby umieszczenie łańcucha w jakimś rodzimym bloku pamięci, do którego można następnie wywołać
ZeroMemory
. Natywny obiekt pamięci, taki jak:SecureString przywraca utraconą zdolność
W .NET ciągi nie mogą być czyszczone, gdy już z nimi skończysz:
Dispose
z nichSecureString istnieje jako sposób na ominięcie bezpieczeństwa ciągów i być w stanie zagwarantować ich czyszczenie w razie potrzeby.
Zadałeś pytanie:
Ponieważ teraz masz
password
w pamięci; bez możliwości jego wyczyszczenia. Utknął tam, dopóki CLR nie zdecyduje się ponownie użyć tej pamięci. Umieściłeś nas tam, gdzie zaczęliśmy; działająca aplikacja z hasłem, którego nie możemy się pozbyć i gdzie zrzut pamięci (lub Process Monitor) może zobaczyć hasło.SecureString używa Data Protection API do przechowywania łańcucha zaszyfrowanego w pamięci; w ten sposób łańcuch nie będzie istniał w plikach wymiany, zrzutach awaryjnych, a nawet w oknie zmiennych lokalnych, gdy kolega powinien się nad nim zastanowić.
Jak odczytać hasło?
Następnie pojawia się pytanie: jak wchodzić w interakcje z ciągiem? Absolutnie nie chcesz takiej metody jak:
ponieważ teraz wracasz do miejsca, w którym zacząłeś - hasła, którego nie możesz się pozbyć. Chcesz zmusić programistów do prawidłowego obchodzenia się z wrażliwym łańcuchem - aby mógł zostać usunięty z pamięci.
Właśnie dlatego .NET zapewnia trzy przydatne funkcje pomocnicze, które pozwalają wprowadzić SecureString do niezarządzanej pamięci:
Przekształcasz ciąg w niezarządzany obiekt blob pamięci, obsłużysz go, a następnie wyczyścisz ponownie.
Niektóre interfejsy API akceptują SecureStrings . Na przykład w ADO.net 4.5 SqlConnection.Credential przyjmuje zestaw SqlCredential :
Możesz także zmienić hasło w ciągu połączenia:
Wewnątrz .NET znajduje się wiele miejsc, w których nadal akceptują zwykły ciąg znaków dla celów kompatybilności, a następnie szybko odwracają go i umieszczają w SecureString.
Jak wstawić tekst do SecureString?
Pozostaje problem:
To wyzwanie, ale chodzi o to, abyś pomyślał o bezpieczeństwie.
Czasami ta funkcja jest już dla Ciebie dostępna. Na przykład kontrolka WPF PasswordBox może zwrócić ci wprowadzone hasło bezpośrednio jako SecureString :
Jest to pomocne, ponieważ wszędzie tam, gdzie przekazywano nieprzetworzony ciąg znaków, teraz system typów narzeka, że SecureString jest niezgodny z ciągiem znaków. Chcesz przejść tak długo, jak to możliwe, zanim będziesz musiał przekonwertować SecureString z powrotem na zwykły ciąg.
Konwersja SecureString jest dość łatwa:
jak w:
Oni naprawdę nie chcą, żebyś to robił.
Ale jak uzyskać ciąg do SecureString? Cóż, musisz przede wszystkim przestać mieć hasło w ciągu znaków . Musiałeś mieć to w czymś innym. Nawet a
Char[]
tablica byłaby pomocna.Właśnie wtedy możesz dołączyć każdą postać i wyczyścić tekst jawny, gdy skończysz:
Musisz hasła zapisanego w jakiejś pamięci, które można wymazać. Załaduj go do SecureString stamtąd.
tl; dr: SecureString istnieje w celu zapewnienia odpowiednika ZeroMemory .
Niektóre osoby nie widzą sensu wymazywania hasła użytkownika z pamięci, gdy urządzenie jest zablokowane , ani wymazywania wymazania klawiszy z pamięci po ich uwierzytelnieniu . Ci ludzie nie używają SecureString.
źródło
Istnieje bardzo niewiele scenariuszy, w których można rozsądnie korzystać z SecureString w bieżącej wersji Framework. Jest to naprawdę przydatne tylko w przypadku interakcji z niezarządzanymi interfejsami API - możesz je uporządkować za pomocą Marshal.SecureStringToGlobalAllocUnicode.
Jak tylko skonwertujesz go na / z System.String, pokonałeś jego cel.
Próbka MSDN generuje znak SecureString naraz z danych wejściowych konsoli i przekazuje bezpieczny ciąg do niezarządzanego interfejsu API. Jest raczej zawiły i nierealny.
Można się spodziewać, że przyszłe wersje platformy .NET będą miały większą obsługę SecureString, dzięki czemu będzie bardziej przydatna, np .:
SecureString Console.ReadLineSecure () lub podobny do odczytu danych wejściowych konsoli do SecureString bez całego skomplikowanego kodu w próbce.
Zastępowanie WinForm TextBox, która przechowuje swoją właściwość TextBox.Text jako bezpieczny ciąg znaków, aby umożliwić bezpieczne wprowadzanie haseł.
Rozszerzenia interfejsów API związanych z bezpieczeństwem, aby umożliwić przekazywanie haseł jako SecureString.
Bez powyższego SecureString będzie miał ograniczoną wartość.
źródło
Uważam, że powodem dodawania znaków zamiast jednej płaskiej instancji jest to, że w tle przekazanie „hasła” do konstruktora SecureString umieszcza ten ciąg „hasła” w pamięci, pokonując cel bezpiecznego ciągu.
Dołączając, zapisujesz tylko znak na raz, który również nie jest fizycznie przylegający do siebie, co znacznie utrudnia odtworzenie oryginalnego łańcucha. Mogłem się tutaj mylić, ale tak mi to wyjaśniono.
Celem tej klasy jest zapobieganie ujawnieniu bezpiecznych danych za pomocą zrzutu pamięci lub podobnego narzędzia.
źródło
MS odkryło, że w niektórych przypadkach powodujących awarię serwera (pulpitu, cokolwiek) zdarzały się sytuacje, w których środowisko wykonawcze wykonywałoby zrzut pamięci odsłaniający zawartość pamięci. Bezpieczny ciąg szyfruje go w pamięci, aby uniemożliwić osobie atakującej odzyskanie zawartości ciągu.
źródło
Jedną z wielkich zalet SecureString jest to, że ma on unikać możliwości przechowywania danych na dysku z powodu buforowania stron. Jeśli masz hasło w pamięci, a następnie załadujesz duży program lub zestaw danych, hasło może zostać zapisane do pliku wymiany, gdy program zostanie stronicowany z pamięci. Dzięki SecureString przynajmniej dane nie będą znajdować się na dysku w nieskończoność w postaci czystego tekstu.
źródło
Chyba dlatego, że ciąg ma być bezpieczny, tzn. Haker nie powinien być w stanie go odczytać. Jeśli zainicjujesz go za pomocą łańcucha, haker może odczytać oryginalny łańcuch.
źródło
Cóż, zgodnie z opisem, wartość jest przechowywana w postaci zaszyfrowanej, co oznacza, że zrzut pamięci procesu nie ujawni wartości łańcucha (bez dość poważnej pracy).
Powodem nie można po prostu skonstruować SecureString z ciągiem stałym jest bo wtedy byłoby mieć niezaszyfrowane wersję napisu w pamięci. Ograniczenie cię do tworzenia łańcucha w kawałkach zmniejsza ryzyko, że cały łańcuch będzie w pamięci na raz.
źródło
Innym przykładem użycia jest praca z aplikacjami płatniczymi (POS) i po prostu nie można używać niezmiennych struktur danych do przechowywania wrażliwych danych, ponieważ jesteś ostrożnym programistą. Na przykład: jeśli będę przechowywać wrażliwe dane karty lub metadane autoryzacji w niezmiennym ciągu, zawsze będzie tak, że dane te będą dostępne w pamięci przez znaczny czas po ich odrzuceniu. Nie mogę tego po prostu zastąpić. Kolejna ogromna zaleta, w której takie wrażliwe dane są przechowywane w pamięci zaszyfrowane.
źródło