2013-01-22 7 views
12

Jest więc ta klasa, która wydaje się bardzo rzadko używana: SecureString. Istnieje już od co najmniej 2.0 i jest kilka pytań SO, ale myślałem, że zadam własne pytania:Bezpieczne używanie SecureString dla formularza logowania

Mam LoginForm; proste okno dialogowe WinForm z nazwą użytkownika i (maskowane) pola hasła. Kiedy użytkownik wchodzi i kliknie "Zaloguj się", informacja jest przekazywana do wstrzykniętej klasy uwierzytelniania, która wykonuje warstwę rozciągania klucza, a następnie haszuje połowę klucza rozciągniętego w celu weryfikacji, podczas gdy druga połowa jest kluczem symetrycznym dla zaszyfrowanego użytkownika dane konta. Kiedy to wszystko się skończy, loginForm zostanie zamknięty, a klasa uwierzytelniająca zlikwidowana, a system przejdzie do ładowania głównego formularza. Całkiem standardowe, może nieco bardziej skomplikowane niż standardowe hash-the-password-and-compare, ale proste hashowane hasło zostanie w moim przypadku pokonane, przechowując dane użytkownika w postaci zwykłego tekstu, ponieważ dane te zawierają dane uwierzytelniające dla trzeciego użytkownika. system imprezowy (i wszyscy wiemy, jak ludzie lubią ponownie używać haseł).

Oto pierwsze pytanie; w jaki sposób używać SecureString do pobrania hasła z pola tekstowego Hasło, bez jest narażone jako zwykłe System.String poprzez właściwość Text pola tekstowego? Zakładam, że istnieje sposób na uzyskanie dostępu do niezarządzanego okna GDI dla pola tekstowego, który jest zawijany przez klasy CLR, i przeciągnij dane tekstowe za pomocą klasy Marshal. Po prostu nie wiem jak i nie mogę znaleźć dobrych informacji.

Oto drugie pytanie; kiedy mam hasło jako SecureString, w jaki sposób mogę przekazać go do dostawcy wartości mieszającej z przestrzeni nazw System.Security.Crypto? Domyślam się, że użyłbym Marshal.SecureStringToBSTR(), a następnie Marshal.Copy() z zwróconego IntPtr z powrotem do tablicy bajtów. Mogę następnie wywołać funkcję Marshal.ZeroBSTR() w celu wyczyszczenia pamięci niezarządzanej i mogę wyzerować zarządzaną tablicę za pomocą metody Array.Clear(), gdy tylko uzyskaję skrót. Jeśli istnieje czystszy sposób, który pozwala mi na pełną kontrolę nad czasem życia każdej zarządzanej kopii pamięci, mów.

Pytanie trzecie; Czy to wszystko jest naprawdę konieczne, czy też nieodłączna niepewność System.String w środowisku pamięci zarządzanej jest trochę przesadzona? Wszystko, co jest używane do przechowywania hasła, szyfrowane lub nie, powinno być poza zakresem i być w drodze do garbage collectora na długo zanim system operacyjny rozważy zamianę aplikacji na pamięć wirtualną (pozwalając na wykradanie hasła z pliku wymiany po ciężkim zamknięciu komputera). Atak typu "zimny but" to teoretyczna możliwość, ale tak naprawdę, jak powszechne jest to? Największym problemem są obecnie odszyfrowane dane użytkownika, które zawieszają się jako część użytkownika przez cały okres użytkowania aplikacji (i dlatego będą głównym kandydatem do używania SecureStrings, ponieważ poza kilkoma podstawowymi zastosowaniami pozostają dość uśpione).

Odpowiedz

5

Jeśli uważasz, że potrzebujesz SecureString, musisz uwierzyć, że atakujący może również odczytać pamięć procesu. Jeśli ta ostatnia jest prawdziwa, może odczytywać znaki hasła podczas ich wpisywania lub odczytywać bezpośrednio z wewnętrznego bufora znaków pola tekstowego lub odczytywać piksele z ekranu.

To nierealistyczny scenariusz. Nie używaj SecureString. Pomaga niewiele i kradnie twój czas.

Ataki typu "cold boot" są bardziej realne, ale niezwykle rzadkie. Wymagają fizycznego dostępu do maszyny, która zazwyczaj całkowicie jest właścicielem maszyny. Czytanie przez atakującego to najmniejszy problem w tym przypadku.

Zasadniczo musisz wymyślić przypadek, w którym Twój czas deweloperajest wydany przy użyciu SecureString.

+6

Chodzi o zmniejszenie powierzchni ataku. Na przykład, jeśli atakujący nie może odczytać pamięci, ale może uzyskać dostęp do pliku wymiany, SecureString może pomóc. Nigdy nie możemy przewidzieć, co atakujący może lub nie może zrobić, więc staramy się uczynić rzeczy najtrudniejszymi dla nich. Ale tak, żadna ilość ochrony nie pomaga: jeśli aplikacja zna informacje - atakujący może również. –

+0

Domyślam się, że najlepszym argumentem przeciwko 'SecureString' jest to, że programista najlepiej spędzić gdzie indziej. – usr

+2

Nie muszę wierzyć, że osoba atakująca może zobaczyć wpisywane znaki, aby uwierzyć, że atakujący może pobrać plik wymiany. Poziom zaawansowania i wymagany dostęp są bardzo różne. Tak więc, mogę przewidzieć przewagę SecureString w niezbyt znanym scenariuszu wymagającym długoterminowych danych wrażliwych przechowywanych w pamięci (takich jak wspomniane wyżej dane uwierzytelniające firm trzecich, które działają tak długo, jak aplikacja działa i mogą z powodzeniem zostać wykorzystane). plik wymiany). Ale myślę, że zgadzam się z twoim punktem widzenia, że ​​9 razy na 10 to więcej problemów, niż jest to warte. – KeithS

3

Przede wszystkim chciałbym stwierdzić, że zgadzam się z usr - nie przejmuj się.

Teraz do szczegółów:

  • This odpowiedź zapewnia doskonałe tło dla dyskusji.
  • This to formant TextBox, który wykorzystuje SecureString. Nie użyłem tego, aby nie komentować jakości, ale będąc na blogu MS nie oczekuj, że będzie to coś innego niż właściwe.
  • Aby odpowiedzieć na pytanie o przekazanie danych do System.Security.Crypto, w zasadzie nie może i żadna ilość niezarządzanego porządkowania pamięci ci nie pomoże, ponieważ podczas procesu takiego rozbierania łańcuch zostanie rozszyfrowany. Musi, bo inaczej nie może być zużyty przez docelowy interfejs API. Jeśli używasz CSP lub X509Certificate, możesz użyć SecureSctring, ponieważ są one obsługiwane w ramach, ale to wszystko.
+0

Nie sądzę, że problem polega na odszyfrowaniu łańcucha (co prawda moja wiedza na ten temat jest lekka). Myślę, że problem polega na utworzeniu System.String, nad którym programista nie ma kontroli pod względem długości życia; jest tworzony na stercie i trzyma się tak długo, jak GC go nie zbiera (co może, ale nie musi nastąpić, zanim zostanie zamienione na VM).Tablica bajtowa, OTOH, może być wyzerowana na miejscu, a niezarządzany IntPtr może być prawidłowo oczyszczony i uwolniony, wszystko to, miejmy nadzieję, w pamięci podręcznej CPU lub RAM, a nie pliku wymiany, ponieważ jest aktywnie używany . – KeithS

+0

Cóż, nie powinieneś naprawdę liczyć na zerowanie tablicy bajtów w miejscu. Odśmiecacz tasuje pamięć przez cały czas, może istnieć wiele kopii twojej tablicy bajtów. Jeśli kierowanie na interfejs API jest zarządzany, masz bardzo niewielką kontrolę nad typem, którego szukasz. –

+0

Jeśli porusza się pamięć GC (jak wiem, że to robi), mam nadzieję, że ma sens, aby posprzątać po sobie w trakcie lub po optymalizacji sterty. Ufam, że GC działa efektywnie z pamięcią, ponieważ nie mogę zrobić nic innego, jeśli chcę w ogóle pracować w zarządzanym środowisku wykonawczym (i robię to, ponieważ jest to * tak * znacznie łatwiejsze niż VC++). Ale wiem, że GC nie jest na moje zawołanie, ponieważ jest to podstawowy problem podczas pisania bezpiecznego kodu w zarządzanych środowiskach wykonawczych. – KeithS

Powiązane problemy