Konwertuj String na SecureString


Odpowiedzi:


137

Ty nie. Cały powód używania obiektu SecureString polega na tym, aby uniknąć tworzenia obiektu typu string (który jest ładowany do pamięci i przechowywany w postaci zwykłego tekstu do czasu wyczyszczenia). Możesz jednak dodawać znaki do SecureString, dołączając je.

var s = new SecureString();
s.AppendChar('d');
s.AppendChar('u');
s.AppendChar('m');
s.AppendChar('b');
s.AppendChar('p');
s.AppendChar('a');
s.AppendChar('s');
s.AppendChar('s');
s.AppendChar('w');
s.AppendChar('d');

13
„Połączenie jest 12345… takie rzeczy ma idiota w swoim bagażu!”
Kanion Kolob,

8
Wszystko, co widzę, to*****
Ian Boyd

AppendCharnie jest wykonywany przed uruchomieniem, więc te znaki można nadal odczytać z IL, prawda? Może przydałoby się również zaciemnianie w czasie kompilacji ... to znaczy, jeśli na stałe wpisujesz hasła.
samis

5
To kiepski argument. Gdzie otrzymujesz hasło? Z formularza lub z wiersza poleceń. Dopóki nie utworzą metody odczytu bezpiecznego ciągu bezpośrednio z urządzenia lub argumentów wiersza poleceń, będziemy musieli przekonwertować ciąg na SecureString.
Quarkly

1
@DonaldAirey otrzymasz hasło od menedżera tajemnic. Ogólnie rzecz biorąc, tajemnice, o których tutaj mówimy, to nie hasła użytkowników, ale rzeczy, które mogą potencjalnie prowadzić do eskalacji uprawnień lub wycieku danych. Oznacza to, że hasła są przeznaczone dla innych usług i nie należy ich podawać w wierszach poleceń ani w sposób jawny przez kanały sieciowe.
Barry Kelly

160

Istnieje również inny sposób konwersji między SecureStringi String.

1. Ciąg do SecureString

SecureString theSecureString = new NetworkCredential("", "myPass").SecurePassword;

2. SecureString to String

string theString = new NetworkCredential("", theSecureString).Password;

Oto link


4
To zdecydowanie najlepsze rozwiązanie w większości przypadków użycia!
Dan Bechard

16
Nie ma sensu używać a, SecureStringjeśli twój kod tworzy stringobiekt o wartości, którą chcesz zabezpieczyć. Celem SecureStringjest uniknięcie umieszczenia ciągu w zarządzanej pamięci, aby osoba atakująca badająca tę pamięć mogła wykryć wartość, którą chcesz ukryć. Ponieważ NetworkCredentialkonstruktor, który wywołujesz, wymaga ciągu, to nie jest droga ... Jasne, twój kod jest łatwym sposobem na konwersję do iz SecureString, ale użycie go sprawia, że ​​twój kod jest tak bezpieczny, jak użycie prostegostring
Gian Paolo

15
@GianPaolo, chociaż teoretycznie jest to poprawne, w praktyce nadal musimy go używać SecureStringpodczas pracy z niektórymi bibliotekami. I bądźmy szczerzy, jeśli ktoś aktywnie skanuje pamięć twojej aplikacji, to już przegrałeś. Nawet jeśli poprawnie użyłeś SecureString, czego nigdy nie widziałem, do wyodrębnienia będą inne cenne dane.
Jonathan Allen

1
@JonathanAllen: Prawdopodobnie masz rację, ale tylko dlatego, że mamy kulturę traktowania bezpieczeństwa jako refleksji. Jeśli tworzysz witrynę z przepisami, Korea Północna prawdopodobnie nie będzie próbować skanować pamięci programu. Jeśli piszesz oprogramowanie bankowe, zagrożenie jest znacznie bardziej realne.
Eric J.

58

poniższa metoda pomaga przekonwertować ciąg na bezpieczny ciąg

private SecureString ConvertToSecureString(string password)
{
    if (password == null)
        throw new ArgumentNullException("password");

    var securePassword = new SecureString();

    foreach (char c in password)
        securePassword.AppendChar(c);

    securePassword.MakeReadOnly();
    return securePassword;
}

26
+1, ale pamiętaj, że przekazanie hasła jako parametru ciągu tworzy niezaszyfrowane wystąpienie ciągu w pamięci zarządzanej i niweczy cel „SecureString” w pierwszej kolejności. Po prostu wskazuję na to przyszłym ludziom, którzy przyjdą i używają tego kodu.
Cody

19
@Cody To prawda i słuszna uwaga, ale wielu z nas nie obchodzi, czy SecureString jest bezpieczny, czy nie i używa go tylko dlatego, że niektóre Microsoft API wymagają go jako parametru.
Dan Bechard,

3
@Cody Okazuje się, że nawet klasa SecureString nie może zachować zaszyfrowanego ciągu. Dlatego firma MS rozważa wycofanie typu github.com/dotnet/platform-compat/blob/master/docs/DE0001.md .
Martin Brown

19

Możesz to śledzić:

string password = "test";
SecureString sec_pass = new SecureString();
Array.ForEach(password.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();

11

Oto tania sztuczka z linq.

            SecureString sec = new SecureString();
            string pwd = "abc123"; /* Not Secure! */
            pwd.ToCharArray().ToList().ForEach(sec.AppendChar);
            /* and now : seal the deal */
            sec.MakeReadOnly();

32
Ta odpowiedź jest ćwiczeniem polegającym na sprawdzeniu, ile tymczasowych kopii zwykłego tekstu można wygenerować za jednym razem
Mike Caron

1
jak @ john-dagg zasugerował, że pomysłem jest NIE ustawianie łańcucha z hasłem, ponieważ jeśli to zrobisz, nie pozostanie żadna korzyść z użycia bezpiecznego łańcucha. W twoim przypadku hasło zostało wpisane w postaci zwykłego tekstu, nic nie zabezpieczasz później, używając bezpiecznego łańcucha. Mam nadzieję, że rozumiesz, że securestring miał zabezpieczyć twój ciąg przed ludźmi oglądającymi demontaż lub debugger, więc zobacz, co jest w IL / pamięci.
user734028

8

Wyrzucę to tam. Czemu?

Nie możesz po prostu zmienić wszystkich swoich ciągów na bezpieczne i nagle Twoja aplikacja jest „bezpieczna”. Bezpieczny ciąg został zaprojektowany tak, aby łańcuch był zaszyfrowany tak długo, jak to możliwe, i był odszyfrowywany tylko przez bardzo krótki czas, czyszcząc pamięć po wykonaniu na nim operacji.

Zaryzykowałbym stwierdzenie, że możesz mieć pewne problemy na poziomie projektowym, z którymi musisz się uporać, zanim zaczniesz martwić się o zabezpieczenie ciągów aplikacji. Podaj nam więcej informacji o tym, co próbujesz zrobić, a być może będziemy w stanie pomóc lepiej.


1
Chcę tylko użyć go do ustawienia hasła dla ProcessStartInfo i uruchomienia mojego exe jako innego użytkownika. To zadziałało dla mnie ...
Developer404

4
Moja aplikacja jest zabezpieczona poprzez uruchomienie jej w bezpiecznym systemie. Nie mogłem mniej przejmować się tym, że ten konkretny ciąg jest zaszyfrowany w pamięci. Jest o wiele ważniejsze informacje o tym systemie, którymi należy się martwić, gdyby kiedykolwiek został narażony. SecureString jest po prostu wymagany przez Microsoft API, z którego mój program musi korzystać. Zakłada się, że deweloper rozważa swój własny przypadek użycia i określa, czy konwersja ciągów znaków na SecureStrings jest prawidłową operacją w kontekście.
Dan Bechard,

Więc ta metoda nie uniemożliwi komuś zobaczenia hasła, jeśli użyje dekompilatora, takiego jak DotPeek? Czy w takim przypadku można ukryć struny?
M.Parent

Istnieje kilka metod, w zależności od zagrożenia, które próbujesz pokonać. Jeśli ma to na celu ochronę informacji użytkowników przed kimkolwiek poza lokalnym administratorem, możesz użyć metod DPAPI w systemie Windows, aby zaszyfrować plik i zapisać tam sekret, odczytać go w bezpiecznym ciągu, a następnie wyrzucić. Jeśli jest to tajemnica firmowa, krótka odpowiedź brzmi: czy Twoja aplikacja może ją odszyfrować, więc ostatecznie może to zrobić użytkownik.
Spence

6
unsafe 
{
    fixed(char* psz = password)
        return new SecureString(psz, password.Length);
}

5

bez fantazyjnego linq, nie dodawanie wszystkich znaków ręcznie, po prostu proste i proste:

var str = "foo";
var sc = new SecureString();
foreach(char c in str) sc.appendChar(c);

nawet bardziej wyszukany, nie ma potrzeby definiowania zmiennej
bigworld12

tutaj jest jedna linijka:var sc = new SecureString(); foreach(char c in "foo") sc.appendChar(c);
bigworld12

4

Zgadzam się ze Spence (+1), ale jeśli robisz to do nauki lub testowania pourpose, możesz użyć foreach w ciągu, dołączając każdy znak do bezpiecznego łańcucha przy użyciu metody AppendChar.


3

Chcę tylko zwrócić uwagę, aby wszyscy ludzie, mówiąc: „To nie jest sens SecureString”, że wielu ludzi zadaje to pytanie może być w aplikacji, w którym, niezależnie od przyczyny, uzasadniony, czy nie, są one nie szczególnie zaniepokojony konieczności tymczasowa kopia hasła znajduje się na stercie jako ciąg znaków GC, ale musi używać interfejsu API, który akceptuje tylkoSecureString obiekty. Masz więc aplikację, w której nic Cię nie obchodziczy hasło jest na stercie, może jest tylko do użytku wewnętrznego, a hasło istnieje tylko dlatego, że jest wymagane przez podstawowe protokoły sieciowe, i okazuje się, że ten ciąg, w którym jest przechowywane hasło, nie może być użyty do np. skonfigurowania zdalnego PowerShell Runspace - ale nie ma łatwego, prostego, jednego liniowca, aby stworzyć to SecureString, czego potrzebujesz. Jest to drobne niedogodności - ale chyba warto, aby zapewnić, że aplikacje, które naprawdę zrobić musi SecureStringnie kusił autorów do użycia System.Stringlub System.Char[]pośredników. :-)


2

Jeśli chcesz skompresować konwersję a stringdo a SecureStringw LINQinstrukcję, możesz to wyrazić w następujący sposób:

var plain  = "The quick brown fox jumps over the lazy dog";
var secure = plain
             .ToCharArray()
             .Aggregate( new SecureString()
                       , (s, c) => { s.AppendChar(c); return s; }
                       , (s)    => { s.MakeReadOnly(); return s; }
                       );

Należy jednak pamiętać, że używanie LINQnie poprawia bezpieczeństwa tego rozwiązania. Cierpi na tę samą wadę, co każda konwersja z stringna SecureString. Dopóki oryginał stringpozostaje w pamięci, dane są podatne na ataki.

Mając to na uwadze, powyższe oświadczenie może zaoferować utrzymanie razem tworzenia pliku SecureString, jego inicjalizację z danymi i ostatecznie zablokowanie go przed modyfikacją.


2

Poniższe 2 rozszerzenia powinny załatwić sprawę:

  1. Dla chartablicy

    public static SecureString ToSecureString(this char[] _self)
    {
        SecureString knox = new SecureString();
        foreach (char c in _self)
        {
            knox.AppendChar(c);
        }
        return knox;
    }
  2. I dla string

    public static SecureString ToSecureString(this string _self)
    {
        SecureString knox = new SecureString();
        char[] chars = _self.ToCharArray();
        foreach (char c in chars)
        {
            knox.AppendChar(c);
        }
        return knox;
    }

Podziękowania dla Johna Dagga za AppendCharrekomendację.


0

możesz użyć tego prostego skryptu

private SecureString SecureStringConverter(string pass)
{
    SecureString ret = new SecureString();

    foreach (char chr in pass.ToCharArray())
        ret.AppendChar(chr);

    return ret;
}

1
Ta odpowiedź została opublikowana 15 miesięcy temu . Naprawdę nie było potrzeby publikowania go ponownie.
GSerg
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.