Wszelkie zastrzeżenia dotyczące zabezpieczenia SecureString poprzez utworzenie Systemu. Pomijając to , jak można to zrobić?
Jak przekonwertować zwykły System.Security.SecureString na System.String?
Jestem pewien, że wielu z was, którzy są zaznajomieni z SecureString, odpowie, że nigdy nie należy przekształcać SecureString w zwykły ciąg .NET, ponieważ usuwa on wszystkie zabezpieczenia. Wiem . Ale w tej chwili mój program i tak robi wszystko za pomocą zwykłych ciągów znaków i próbuję zwiększyć jego bezpieczeństwo i chociaż zamierzam używać interfejsu API, który zwraca do mnie SecureString, nie próbuję go używać do zwiększenia mojego bezpieczeństwa.
Znam Marshal.SecureStringToBSTR, ale nie wiem, jak wziąć ten BSTR i utworzyć z niego System.String.
Dla tych, którzy mogą chcieć wiedzieć, dlaczego kiedykolwiek chciałbym to zrobić, cóż, biorę hasło od użytkownika i przesyłam je jako formularz HTML POST, aby zalogować użytkownika na stronie internetowej. Więc ... to naprawdę musi być zrobione z zarządzanymi, niezaszyfrowanymi buforami. Gdybym mógł nawet uzyskać dostęp do niezarządzanego, niezaszyfrowanego bufora, wyobrażam sobie, że mógłbym zapisywać strumień bajt po bajcie w strumieniu sieciowym i mieć nadzieję, że dzięki temu hasło będzie bezpieczne przez całą drogę. Liczę na odpowiedź na przynajmniej jeden z tych scenariuszy.
źródło
StopWatch
iSecureStringToString
zajęło mi to 4,6 sekundy. Dla mnie jest za wolno. Czy ktoś ma ten sam czas czy coś szybciej?Database.GetConnectionString()
do twojego kodu, aby uzyskać bezpieczny ciąg, który był złą częścią, która zajęła prawie 5 sekund (i tak, powinienem się temu przyjrzeć! :) Twój kod zajął .00 miliardów sekund w moim stoperze, więc jest wszystko dobrze. Dzięki za wskazanie mi właściwego kierunku.Oczywiście wiesz, jak to podważa cały cel SecureString, ale i tak to powtórzę.
Jeśli chcesz mieć jedną linijkę, spróbuj tego: (tylko .NET 4 i nowsze)
Gdzie securePassword to SecureString.
źródło
[System.Net.NetworkCredential]::new('', $securePassword).Password
''
nie jest tego samego typu co[String]::Empty
? RównieżNew-Object Net.Credential
nie działa dla mnie: nie można znaleźć typu [Net.Credential]: sprawdź, czy zestaw zawierający ten typ jest załadowanyCholera. zaraz po opublikowaniu tego znalazłem odpowiedź głęboko w tym artykule . Ale jeśli ktoś wie, jak uzyskać dostęp do niezarządzanego, niezaszyfrowanego bufora IntPtr, który ta metoda ujawnia, po jednym bajcie na raz, aby nie musieć tworzyć z niego zarządzanego obiektu ciągu, aby utrzymać wysokie bezpieczeństwo, dodaj odpowiedź. :)
źródło
unsafe
słowa kluczowego i achar*
, po prostu zadzwońbstr.ToPointer()
i rzuć.SecureString.Length
.SecureString
nie próbuje ukryć wartości, stara się zapobiec tworzeniu kopii wartości w regionach, których nie można niezawodnie nadpisać, takich jak pamięć zebrana bezużyteczna, plik stronicowania, itp. Celem jest, aby po zakończeniuSecureString
okresu życia absolutnie żadna kopia tajemnicy nie pozostaje w pamięci. Nie zapobiega tworzeniu i wyciekaniu kopii, ale nigdy tak nie jest.Moim zdaniem metody rozszerzające są najwygodniejszym sposobem rozwiązania tego problemu.
Wziąłem Steve'a w doskonałej odpowiedzi CO i umieściłem go w klasie rozszerzającej w następujący sposób, wraz z drugą metodą, którą dodałem, aby obsługiwać również drugi kierunek (ciąg -> bezpieczny ciąg), dzięki czemu możesz utworzyć bezpieczny ciąg i przekonwertować go na potem normalny ciąg:
Dzięki temu możesz teraz po prostu konwertować ciągi znaków w tę iz powrotem w następujący sposób:
Należy jednak pamiętać, że metoda dekodowania powinna być używana tylko do testowania.
źródło
Myślę, że najlepiej byłoby, gdyby
SecureString
funkcje zależne hermetyzowały swoją zależną logikę w funkcji anonimowej, aby uzyskać lepszą kontrolę nad odszyfrowanym ciągiem w pamięci (po przypięciu).Implementacja do odszyfrowywania SecureStrings w tym fragmencie:
finally
bloku.To oczywiście znacznie ułatwia „standaryzację” i utrzymanie dzwoniących w porównaniu z poleganiem na mniej pożądanych alternatywach:
string DecryptSecureString(...)
funkcji pomocniczej.Zauważ, że masz dwie opcje:
static T DecryptSecureString<T>
który umożliwia dostęp do wynikuFunc
delegata z wywołującego (jak pokazano wDecryptSecureStringWithFunc
metodzie testowej).static void DecryptSecureString
jest po prostu wersją "void", która zatrudniaAction
delegata w przypadkach, gdy faktycznie nie chcesz / nie musisz niczego zwracać (jak pokazano wDecryptSecureStringWithAction
metodzie testowej).Przykładowe użycie dla obu można znaleźć w
StringsTest
dołączonej klasie.Strings.cs
StringsTest.cs
Oczywiście nie zapobiega to nadużywaniu tej funkcji w następujący sposób, więc po prostu uważaj, aby tego nie robić:
Miłego kodowania!
źródło
Marshal.Copy(new byte[insecureString.Length], 0, insecureStringPointer, (int)insecureString.Length);
zamiastfixed
sekcji?[char]
, nie[byte]
.String.Empty
, a nie nowo przydzielona instancja utworzona i zwrócona przezMarshal.PtrToStringUni()
.Stworzyłem następujące metody rozszerzające na podstawie odpowiedzi z rdev5 . Przypięcie zarządzanego ciągu jest ważne, ponieważ zapobiega przenoszeniu go przez moduł wyrzucania elementów bezużytecznych i pozostawianiu kopii, których nie można usunąć.
Myślę, że zaletą mojego rozwiązania jest to, że nie jest potrzebny żaden niebezpieczny kod.
źródło
System.String
obiekcie spowoduje utworzenie odpiętych i nieskasowanych kopii. Dlatego nie jest to wbudowaneSecureString
.new char[length]
(lub pomnożyćlength
przezsizeof(char)
).action
delegat nie utworzy kopii tymczasowego, przypiętego, a następnie zerowanego ciągu, to podejście powinno być równie bezpieczne lub niebezpieczne jakSecureString
samo - aby użyć tego drugiego, reprezentacja w postaci zwykłego tekstu również musi zostać utworzone w pewnym momencie, biorąc pod uwagę, że bezpieczne łańcuchy nie są konstrukcjami na poziomie systemu operacyjnego; względne bezpieczeństwo wynika z kontrolowania żywotności tego ciągu i zapewnienia, że zostanie on usunięty po użyciu.SecureString
nie ma funkcji składowych i przeciążonych operatorów, które tworzą kopie w każdym miejscu.System.String
robi.NetworkCredential
konstruktorowi, który akceptuje plikSecureString
.Ten kod C # jest tym, czego chcesz.
%ProjectPath%/SecureStringsEasy.cs
źródło
Wyprowadziłem z tej odpowiedzi przez sclarke81 . Podoba mi się jego odpowiedź i używam pochodnej, ale sclarke81 ma błąd. Nie mam reputacji, więc nie mogę komentować. Problem wydaje się na tyle mały, że nie wymagał innej odpowiedzi i mogłem go edytować. Więc zrobiłem. Został odrzucony. Więc teraz mamy inną odpowiedź.
sclarke81 Mam nadzieję, że zobaczysz to (w końcu):
Powinien być:
I pełna odpowiedź z poprawką błędu:
źródło
Ostateczne rozwiązanie robocze zgodne z rozwiązaniem sclarke81 i poprawkami Johna Flaherty'ego to:
źródło
źródło
BSTR
jawnie i nie jest to obiekt .NET, więc garbage collector też się tym nie zajmuje. Porównaj ze stackoverflow.com/a/818709/103167, który został opublikowany 5 lat wcześniej i nie wycieka.Jeśli użyjesz a
StringBuilder
zamiast astring
, możesz nadpisać rzeczywistą wartość w pamięci, kiedy skończysz. W ten sposób hasło nie będzie wisiało w pamięci, dopóki nie zostanie odebrane przez funkcję czyszczenia pamięci.źródło