Laden...

SecureString nach char[] umwandeln?

Erstellt von Weressated vor einem Jahr Letzter Beitrag vor einem Jahr 1.836 Views
Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr
SecureString nach char[] umwandeln?

Hallo.

Ich verwende eine WPF PasswortBox um das Passwort vom Benutzer entgegenzunehmen. Das Passwort wird wird als SecureString abgerufen, damit es nicht als Klartext im Speicher liegt.

So weit, so gut. Leider unterstützen allerdings nicht alle Funktionen SecureString. Eine Funktion, die ich benutzen muss (nicht mein Code!), will das Passwort als char[] Array.

Wie also kann ich ein SecureString in ein char[] Array umwandeln?

Ich habe bereits folgenden Code bei CodeProject gefunden, der eine SecureString in ein "normales" String umwandelt:


public string convertToUNSecureString(SecureString secstrPassword)
{
    IntPtr unmanagedString = IntPtr.Zero;
    try
    {
        unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secstrPassword);
        return Marshal.PtrToStringUni(unmanagedString);
    }
    finally
    {
        Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
    }
}

Ab dem Punkt könnte man natürlich einfach String.ToCharArray() benutzen. Allerdings möchte man die Umwandlung von SecureString nach String natürlich vermeiden!

Denn String ist bekanntlich immutable und kann man nicht überschreiben! Das Passwort bleibt auf unbestimmte Zeit im Speicher 😡

Bei einem char[] Array hat man das Problem nicht. Da kann man die sensiblen Daten z.B. mit Array.Clear() sofort überschreiben, wenn sie nicht mehr gebraucht würden.

Daher die Frage: Kann man SecureString irgendwie ohne den Umweg über ein String-Instanz direkt als char[] Array bekommen ???

Danke!

(Hinweis: Mir ist klar, dass wenn eine Funktion SecureString nicht direkt benutzen kann, die Daten so oder so zumindest "temporär" als Klartext im Speicher liegen)

4.931 Beiträge seit 2008
vor einem Jahr

Hallo,

vielleicht hilft dir die Klasse SecureStringWrapper sowie dessen Methode ToByteArray aus der Antwort von Converting a SecureString to a byte array (als Verbesserung des Codes, welche sehr deinem bisherigen Code ähnelt, aber Marshal.SecureStringToBSTR nun verwendet - inklusive Überschreiben der Daten in der Dispose-Methode)?

16.806 Beiträge seit 2008
vor einem Jahr

Das Passwort wird wird als SecureString abgerufen, damit es nicht als Klartext im Speicher liegt.

Das ist leider ein Irrtum - und man soll den SecureString schon ewig nicht mehr benutzen. Er "verspricht" Sicherheit, die es nicht gibt.
Obsolete the SecureString type #30612

Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr

Hallo,

vielleicht hilft dir die Klasse SecureStringWrapper sowie dessen Methode ToByteArray aus der Antwort von
>
(als Verbesserung des Codes, welche sehr deinem bisherigen Code ähnelt, aber Marshal.SecureStringToBSTR nun verwendet - inklusive Überschreiben der Daten in der Dispose-Methode)?

Danke für den Hinweis auf Marshal.SecureStringToBSTR()!

Die Konvertierung in Bytes benötige nicht, aber man kann mit Marshall.Copy() direkt die char's raus kopieren 👍


    class SecureStringReader : IDisposable
    {
        public char[] Buffer { get; private set; } = Array.Empty<char>();

        public SecureStringReader(SecureString secureStr)
        {
            if ((secureStr != null) && (secureStr.Length > 0))
            {
                IntPtr temp = IntPtr.Zero;
                try
                {
                    char[] buffer = new char[secureStr.Length];
                    if ((temp = Marshal.SecureStringToBSTR(secureStr)) != IntPtr.Zero)
                    {
                        Marshal.Copy(temp, buffer, 0, secureStr.Length);
                        Buffer = buffer;
                    }
                }
                finally
                {
                    Marshal.ZeroFreeBSTR(temp);
                }
            }
        }

        public void Dispose()
        {
            Array.Clear(Buffer, 0, Buffer.Length);
        }
    }

Das ist leider ein Irrtum - und man soll den SecureString schon ewig nicht mehr benutzen. Er "verspricht" Sicherheit, die es nicht gibt.
Obsolete the SecureString type #30612

Naja, wenn man das mal im Detail liest:

DE0001: SecureString shouldn't be used
Motivation
The purpose of SecureString is to avoid having secrets stored in the process memory as plain text.

However, even on Windows, SecureString doesn't exist as an OS concept.

The contents of the array is unencrypted except on .NET Framework.

In .NET Framework, the contents of the internal char array is encrypted. .NET doesn't support encryption in all environments, either due to missing APIs or key management issues.

Recommendation
Don't use SecureString for new code. When porting code to .NET Core, consider that the contents of the array are not encrypted in memory.

...dann ist das "Problem" doch lediglich, dass SecureString keine 100% Sicherheit bietet, sondern "nur" die Dauer das Angriffs-Fenster verkürzt. Was eben daran liegt, dass der String, wenn er benutzt wird, zumindest temporär wieder als Klartext entschlüsselt werden muss.

Naja, kann man so sehen. Ich finde aber, die Zeitdauer, die das Passwort als Klartext im Speicher liegt, auf das nötige Minimum zu begrenzen, ist immer noch ein Vorteil – gegenüber der Alternative, dass das Passwort als "normaler" String für undefinierte Zeit als Klartext im Speicher rum liegt 😉

(Und .NET Core ist für mich im Moment nicht relevant)

16.806 Beiträge seit 2008
vor einem Jahr

Les den Artikel und die angehängten Design Issues vielleicht ganz. Deswegen hab ichs Dir geschickt. Das TLDR hast bekommen.
Das Problem ist, dass die SecureString Implementierung suboptimal ist, was dazu führt, dass Reihenweise Firmen durch Security Audits fliegen.

Barry Dorrans ist bei Microsoft der .NET Security PM. Schau Dir seine Artikel / Talks dazu an.
Oder schau seine Kommentare auf Twitter dazu an: SecureString from:blowdart

Fazit dazu:


>

It takes way more nuance than a tweet to talk about why SecureString sucks


>

Stop using SecureString.

Hat mit .NET Core nichts zutun.

Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr

Les den Artikel und die angehängten Design Issues vielleicht ganz. Deswegen hab ichs Dir geschickt. Das TLDR hast bekommen.

Ja, hab ich. Die einzigen "Argumente", die gegen eine Verwendung von SecureString sprechen, die dort genannt werden, sind:* SecureString könnte beim Entwickler falsche Erwartungen wecken.
⇒ Das ist natürlich komplett subjektiv 🙄

  • SecureString ist nicht 100% sicher, weil die Daten bei Verwendung doch wieder temporär entschlüsselt werden müssen und dann kurzzeitig als Klartext vorliegen.
    ⇒ Das wäre ein Argument, wenn es denn eine bessere Alternativ gäbe. Die wurde bisher aber noch nicht aufgezeigt. Ein "normaler" ungeschützter String bietet jedenfalls überhaupt keine Sicherheit, weil die Daten dann einfach die ganze Zeit als Klartext im Speicher rumliegen (anstatt wie bei SecureString nur hin und wieder für ein paar Millisekunden), und man sie am Schluss noch nicht mal explizit abräumen kann 😉

  • In manchen Umgebungen, wo keine Verschlüsselung unterstützt wird, ist SecureString komplett unverschlüsselt (betrifft anscheinend nur .NET Core)
    ⇒ Damit ist SecureString also im schlimmsten Fall genau so unsicher wie ein "normaler" String, im Normalfall (und bei .NET Framework immer) biete SecureString aber eine zusätzliche Sicherheit gegenüber String. Eine noch bessere Alternative zu SecureString ist auch hier wieder nicht genannt worden 😉

Kurz gesagt: Die Argumentation ist letzten Endes immer die, dass SecureString nicht "perfekt" sicher ist, und man deshalb mangels besserer Alternative (jedenfalls wird ja keine genannt) einfach keine(?) Sicherheit haben sollte...

Überzeugt mich noch nicht so ganz 😜

Recommendation
The general approach of dealing with credentials is to avoid them and instead rely on other means to authenticate, such as certificates or Windows authentication.

Dieser Tipp nützt bloß herzlich wenig, wenn man in einer realen Anwendung ein Passwort per PasswortBox entgegennehmen und an eine Bibliothek (nicht mein Code!) übergeben muss, die nun einmal ein char[] Array haben will 😲

Das Problem ist, dass die SecureString Implementierung suboptimal ist, was dazu führt, dass Reihenweise Firmen durch Security Audits fliegen.

Ein Audit, das dogmatisch bestimmte Dinge beanstandet ohne den Kontext zu berücksichtigen und ohne ein bessere+praktikable Alternative vorzuschlagen, ist reichlich sinnfrei.

Werden wir doch mal konkret:
Was ist denn der "empfohlene" Weg, um ein Passwort aus einer PasswortBox entgegen zu nehmen und weiter zu verarbeiten? Soweit ich sehe, kann man das Passwort entweder als String abrufen, was offensichtlich komplett unsicher ist, da das Passwort dann die ganze Zeit als Klartext im Speicher liegt, oder man kann das Passwort als SecureString abrufen, was zwar nicht "perfekt" sicher aber auf jeden Fall sehr viel sicherer als ein "normaler" ungeschützter String ist. Eine weitere Option sehe ich nicht...

So, oder so. Dein Kollege hat ja bereits die ursprüngliche Frage beantwortet. Nochmal danke dafür!

16.806 Beiträge seit 2008
vor einem Jahr

Meinst nicht es wäre schlauer und effizienter einfach mal die Basics zuzuhören, die der .NET Security PM erklärt, statt Halbwissen aufzuzählen und Beiträge 27 mal zu editieren? 😉
Willst ja eine sichere Lösung - und die geht mit SecureString nicht. Es gibt nämlich keine sichere Lösung für das Halten von Credentials im Speicher. Deswegen ist der SecureString ein Irrtum. Egal ob Char Array oder String.

Einzig sichere Lösung: externe Passwortverwaltung und Flows wie OAuth nehmen. Damit besteht man auch moderne Security Audits.
Das sagt Dir auch Microsoft, Google, Amazon, Okta...

Aber Du kannst auch einen eigenen Standpunkt haben, und es besser wissen als der .NET Security PM oder die Identity Profis 😉

Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr

Einzig sichere Lösung: externe Passwortverwaltung und Flows wie OAuth nehmen. Damit besteht man auch moderne Security Audits.
Das sagt Dir auch Microsoft, Google, Amazon, Okta...

Alles wunderbare Lösungen... für andere Probleme 🙄

Nachmal: Es geht hier ganz konkret darum, dass eine Bibliotheks-Funktion (konkret eine Funktion aus BouncyCastle) aufgerufen werden muss, die ein Passwort als char[] Array entgegen nimmt. Das Passwort muss per GUI entgegen genommen werden, naheliegender Weise per PasswortBox, wobei hier theoretisch ein anderes Control herhalten könnte.

Bis jetzt habe ich noch von Dir noch nichts konkretes gehört, wie man das besser (sicherer) als mit einem SecureString lösen kann 😉

SecureString ist nicht "perfekt" sicher. Das haben wir verstanden. So what? Die Welt ist nicht schwarz/weiß. Eine "perfekte" Lösung gibt es in den seltensten Fällen. Deshalb muss man nicht gleich hinwerfen oder die schlechteste aller Lösungen nehmen. Es geht immer darum, mit den verfügbaren Möglichkeiten eine möglichst gute Lösung zu finden. Wenn ich also zwischen String (⇒ gar keine Sicherheit) und SecureString (⇒ weitestgehend sicher, mit bekannten Einschränkungen) wählen kann, um das Passwort zu sichern, dann werde ich doch immer SecureString nehmen! Für Alternativvorschläge bin ich jederzeit offen, aber sie müssen halt schon zum konkreten Anwendungsfall passen...

Aber Du kannst auch einen eigenen Standpunkt haben, und es besser wissen als der .NET Security PM oder die Identity Profis 😉

Aussagen wie "SecureString is not suitable for anything... Stop using SecureString" sind ganz klar undifferenziertes Clickbait.

Es gibt auch differenzierte Betrachtungen:

There is no alternative to the SecureString class. So, if you really need the credentials [...] use SecureString:
https://stackoverflow.com/a/55590953

SecureString is "discouraged by Microsoft" - that's an oversimplification:
https://stackoverflow.com/a/55590962

SecureString is a good and right idea. The reason Microsoft no longer recommends it is because .NET Core can't have it:
https://stackoverflow.com/a/67048259

16.806 Beiträge seit 2008
vor einem Jahr

Bis jetzt habe ich noch von Dir noch nichts konkretes gehört, wie man das besser (sicherer) als mit einem SecureString lösen kann 😉

Nich jedem ist das Lesen in die Wiege gelegt; helfe aber gerne nach.

Es gibt nämlich keine sichere Lösung für das Halten von Credentials im Speicher. Deswegen ist der SecureString ein Irrtum. Egal ob Char Array oder String.

Einzig sichere Lösung: externe Passwortverwaltung und Flows wie OAuth nehmen. Damit besteht man auch moderne Security Audits.
Das sagt Dir auch Microsoft, Google, Amazon, Okta...

Die bittere Realität: ein String /Char Array ist genauso sicher / unsicher wie ein SecureString. SecureString macht absolut nichts sicherer.
Auch das Thema "das Passwort ist nur kurz im Speicher" ist kein Argument, weil der Zeitfaktor völlig irrelevant für Angriffsvektoren ist. Das dachte man mal vor 20 Jahren…heute weiß man das besser.
=> Befass Dich mit dem Speichermanagement von Windows; vielleicht verstehst es dann.

Hättest auch nur ein mal nen Artikel dazu von Barry gelesen; oder wenigstens die Kommentare von Deinen eigenen StackOverflow Links. Würde viel hier zu lesendes Halbwissen ersparen.
Auf SO ist nichts differenziert - das ist ziemlich eindeutig. Stattdessen wird irgendwas zusammen kopiert, miteinander vermischt und aus dem Kontext gerissen.

Auch in Deinen SO wird Barry zitiert - vielleicht ist der doch eine valide Quelle, so als Security PM.... ah ne. Stimmt. Er macht ja Clickbait, wie Du sagst 🙂


>

Shawn we simply don't believe it has any protection in the real world. At some point, to get used, it gets turned back into a string and all bets are off. We haven't recommended it in years

Und .NET Core hat keinen SecureString, weil das unter Linux nicht möglich ist; die APIs fehlen.
Linux hat dafür keine APIs weil - Achtung Trommelwirbel - es keine sichere Möglichkeit gibt.

Viel Erfolg.

T
2.219 Beiträge seit 2008
vor einem Jahr

Insgesamt hat Abt hier absolut Recht.
Die Frage die man sich auch stellen muss ist ob eure Anwendung zukünftig auch unter neueren .NET Versionen laufen soll und ggf. auf anderen Platformen wie Linux.
Ab dem Punkt würdet ihr mit SecureString auf die Nase fallen, was ihr auch vermeiden solltet.

Hier stehen in den Links auch einige Ansätze.
Wie gut diese sind kann ich nicht zu 100% beurteilen.

Wenn ihr gegen eine Lib arbeiten müsst, die schon die Klartextdaten verlangt, was genau bringt dann die Kapselung in SecureString?
Zwar lagern die Daten dann in einem SecureString, wenn man die Daten aber zwischen dem speichern und dem auslesen zwischen Klartext und SecureString abgreift hast du 0% Sicherheit dadurch.
Ein Zeitfenster spielt dabei dann auch keine Rolle, dass ist es auch was Abt damit ausdrücken will.
Wenn jemand in deinem Prozess die Daten abgrasen kann, dann spielt es auch keine Rolle wie lange die Daten im Speicher vorliegen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr

Wenn ihr gegen eine Lib arbeiten müsst, die schon die Klartextdaten verlangt, was genau bringt dann die Kapselung in SecureString?

Wenn Du sensible Informationen wie Passwörter in einen "normalen" String packst, dann liegen die Daten dauerhaft im Klartext im Speicher. Weil String immutable ist, können die Daten nicht explizit überschrieben werden. Wann der GC mal irgendwann den betreffenden String abräumt, und wann dann evtl. mal irgendwann dieser Speicherbereich wiederverwendet und mit neuen Daten überschrieben wird, das ist völlig undefiniert und wird i.d.R. nicht zeitnah passieren.

Mit einem SecureString liegen die sensible Informationen nahezu die gesamte Zeit über nur verschlüsselt im Speicher und tauchen dann z.B. in einem Memory-Dump nicht auf. Ja, richtig, um mit den Daten rechnen zu können, müssen sie notwendigerweise temporär entschlüsselt werden. Aber, mit der oben beschrieben Methode werden die Daten aus dem SecureString direkt in ein char[] Array entschlüsselt und nach der Berechnung auch sofort wieder überschrieben. Die Bibliotehk kopiert diese Daten auch nicht. Damit liegen die sensiblen Daten also nur noch für den Bruchteil einer Sekunde als Klartext im Speicher – anstatt dauerhaft. Das ist eindeutig erheblich sicherer als die Alternative, und definitiv nicht von Nachteil.

Wenn jemand in deinem Prozess die Daten abgrasen kann, dann spielt es auch keine Rolle wie lange die Daten im Speicher vorliegen.

Ein Zeitfenster spielt dabei dann auch keine Rolle, dass ist es auch was Abt damit ausdrücken will.

Doch, das tut es sehr wohl. Wenn die Daten nur für den Bruchteil einer Sekunde im Speicher liegen, ist es sehr viel unwahrscheinlicher, dass jemand sie genau in dem Moment erfolgreich abgreifen kann, als wenn sie dauerhaft dort rumliegen würde. Aber es geht auch darum, dass sensible Daten in Crash-Dumps oder dem Hibernation-File, etc. pp. auftauchen können. Ja, sogar nach einem Reboot können noch "alte" Daten aus dem RAM auslesbar sein (siehe Kaltstartattacke).

Praktisch jede Crypto-Bibliothek wie z.B. OpenSSL und Co. arbeiten deshalb genau so: Sensible Daten, wie Passwörter oder Schlüssel, werden stets nur so lange wie für die Berechnung unbedingt nötig als Klartext im Speicher gehalten, und sofort danach mit SecureZeroMemory() bzw. explicit_bzero() wieder ausradiert. Genau für diesen Zweck existieren solche Funktionen. Genau so wirst Du bei einem Blick in die JCE (Java Cryptography Extension) sehen, dass dort alle sensiblen Daten (Schlüssel, Passwörter, temporäre Zwischenergebnisse) immer sofort nach Benutzung sehr sorgfältig mit Arrays.fill(secret, (byte)0) wieder überschrieben werden.

Dass Du sensible Daten zumindest temporär als Klartext im Speicher halten musst, um damit rechnen zu können, ist oftmals unvermeidlich – außer vielleicht Du verlagerst die Berechnung komplett in einen separaten Sicherheitschip (TMP, SmartCard, etc.), aber das ist hier nicht Thema – deshalb muss man doch nicht gleich jegliche Sicherheit über Board werfen. Es geht letztlich immer darum, das Angriffsfenster so klein wie möglich zu halten.

Nochmal: Schwarz-Weiß-Denken und undifferenzierte Aussagen wie "XZY ist nicht perfekt sicher und muss deshalb tausend Mal verteufelt werden!" helfen uns hier nicht weiter. Es geht viel mehr darum, im konkreten Anwendungsfall mit den verfügbaren Mitteln eine möglichst gute und praktikable Lösung zu finden. Wenn es konkrete Vorschläge gibt, wie man in dem konkreten Anwendungsfall die Sicherheit noch weiter verbessern kann, dann bin ich dafür dankbar. Aber, darauf zu beharren, dass bereits genutzte Sicherheitsmechanismen über Board geworfen werden soll, ohne gleichzeitig eine bessere Alternative anzubieten, ist und bleibt komplett kontraproduktiv... Und nein, einfach mal irgendwelche Lösungen als Buzzword in den Raum zu werfen, obwohl diese gar nicht für den betrachteten Anwendungsfall zutreffend sind, zählt nicht 😉

Die Frage die man sich auch stellen muss ist ob eure Anwendung zukünftig auch unter neueren .NET Versionen laufen soll und ggf. auf anderen Platformen wie Linux.
Ab dem Punkt würdet ihr mit SecureString auf die Nase fallen, was ihr auch vermeiden solltet.

Nach Quellenlage ist SecureString bei .NET Core in "bestimmten Umgebungen wo keine Verschlüsselung zur Verfügung steht" nicht verschlüsselt und damit dann genau so unsicher wie ein "normaler" String. So what? Damit wäre SecureString im schlimmsten Fall genau so unsicher wie String, in den meisten Umgebungen (und bei einem .NET Framework immer) aber viel sicherer. Etwas verlieren tust Du damit also auf keine Fall, außer evtl. ein klein wenig Performance. Du kannst also nur etwas gewinnen!

A
764 Beiträge seit 2007
vor einem Jahr

Im Endeffekt ist das eine "security through obscurity"-Diskussion. Ich denke die Argumente für und wieder sind im Netzt zur genüge ausgetauscht.
Ich für meinen Teil kann nur empfehlen bei Security-Themen immer auf etablierte Systeme zu gehen und sowas nicht selber zu machen. 😉

16.806 Beiträge seit 2008
vor einem Jahr

Alf Ator absolut. Das dreht sich super im Kreis und mittlerweile eine riesen Ansammlung an zusammen kopiertem Halbwissen.
Soll Weressated das halt so machen. Wir haben hier nur die Macht zu Beraten, nicht zu entscheiden oder zu verantworten.

Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr

Im Endeffekt ist das eine "security through obscurity"-Diskussion. Ich denke die Argumente für und wieder sind im Netzt zur genüge ausgetauscht.

Nö. Security through obscurity heißt, dass ein Sicherheitsmechanismus nur solange "sicher" ist, wie die genaue Funktionsweise geheim gehalten wird. Das Gegenteil von Kerckhoffs’ Prinzip

Dass man sensible Daten nur wenn unbedingt nötig und – wenn nicht anders möglich – immer nur so kurz wie unbedingt erforderlich (als Klartext) im Speicher hält, ist hingegen eine völlig "transparente" und allgemein bekannte Vorgehensweise; es ist ganz einfach "Best Practice" in der Softwareentwicklung und wird, wie schon erwähnt, in gängigen Security-Bibliotheken genau so umgesetzt.

The Secure­Zero­Memory() function doesn’t make things secure; it just makes them more secure. The issue is a matter of degree, not absolutes.
https://devblogs.microsoft.com/oldnewthing/20130529-00/?p=4223

...an der Stelle könntest Du anstatt Secure­Zero­Memory() auch SecureString oder andere einsetzen 😉

Die ganze Diskussion gegen die Verwendung von SecureString, die hier geführt wurde, basiert hauptsächlich auf Strohmann-Argumenten, d.h. es wird die ganze Zeit gegen eine vermeintliche "absolute Sicherheit" argumentiert, die so aber ja niemals behauptet wurde (und die es natürlich i.d.R. auch nicht geben kann). Wie Raymond Chen schon richtig gesagt hat: "the issue is a matter of degree, not absolutes".

Ich für meinen Teil kann nur empfehlen bei Security-Themen immer auf etablierte Systeme zu gehen und sowas nicht selber zu machen. 😉

Da stimme ich Dir vollkommen zu. "Don't roll your own crypto" 🙂

Deshalb vorhandene und etablierte Sicherheitsmechanismen wie, z.B. (aber nicht beschränkt auf) SecureString nutzen, wo verfügbar und zum Anwendungsfall passend, anstatt zu versuchen das Rad neu zu erfinden.

Wenn es keine perfekte Lösung gibt – und die wird es in der Realität selten geben – nimm halt wenigstens die beste verfügbare/praktikable Lösung 👍

Siehe auch:
https://stackoverflow.com/a/67048259

A
764 Beiträge seit 2007
vor einem Jahr

Die Obscurity ist in dem Fall, dass das Passwort nur kurz im Speicher gehalten wird. Wenn man das weiss, dann kann man seinen Angriff entsprechende danach ausrichten.

Das SecureString sicherer ist, als String, bestreite ich gar nicht. Mein Kritikpunkt geht eher dahin, den Passwort-Dialog selber zu erstellen, ergo Security selber zu machen. Das mag für deinen Anwendungsfall okay sein. In der Praxis sehe ich aber immer wieder, dass Firmen versuchen auf diese Weise Kundendaten zu schützen. Adressdaten, Bank-Verbindungen, Patientenakten. So ein Security-Vorfall, kann auch locker einer grösseren Firma den Kopf kosten, von den geschädigten Personen ganz zu schweigen.

Ich kann meine Empfehlung nur nochmal wiederholen, für Security etablierte Systeme zu benutzen. Das kommt natürlich drauf an, wie der UseCase ist. In einer Windows-Domain würde man also ActiveDirectory verwenden, im Web einen passenden Anbieter.

Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr

Die Obscurity ist in dem Fall, dass das Passwort nur kurz im Speicher gehalten wird. Wenn man das weiss, dann kann man seinen Angriff entsprechende danach ausrichten.

"Security through obscurity" bedeutet ja, dass sich die Sicherheit in quasi Luft auflöst, wenn man weiß, wie das Verfahren funktioniert. Die Sicherheit basiert auf Geheimhaltung des Verfahrens selbst.

Sensible Daten nur so kurz wie möglich im Speicher zu halten (anstatt längerfristig) ist aber generell sinnvoll und macht es einem potentiellen Angreifer viel schwerer diese Daten abzugreifen, egal ob dieser davon weiß, dass die Daten nur kurzfristig da sein werden oder ob er das nicht weiß. Von daher hinkt der Vergleich meiner Meinung 😉

Mein Kritikpunkt geht eher dahin, den Passwort-Dialog selber zu erstellen, ergo Security selber zu machen. Das mag für deinen Anwendungsfall okay sein. In der Praxis sehe ich aber immer wieder, dass Firmen versuchen auf diese Weise Kundendaten zu schützen. Adressdaten, Bank-Verbindungen, Patientenakten. So ein Security-Vorfall, kann auch locker einer grösseren Firma den Kopf kosten, von den geschädigten Personen ganz zu schweigen.

Auch hier wieder die Frage, was ist konkret die bessere Alternative?

Wie schon mehrmals betont, geht es hier von Anfang an um den Anwendungsfall, dass ein "Passwort" an eine Bibliotheks-Funktion (konkret BouncyCastle) als char[] Array übergeben werdenmuss, um damit eine notwendige Berechnung auszuführen. Das Passwort muss irgendwie vom Benutzer entgegen genommen werden, um es an die Bibliothek übergeben zu können. Die Bibliothek kann bzw. soll nicht verändert werden. Die Frage war lediglich, wie man das Passwort, das von der PasswortBox als SecureString zurück geliefert wird, am besten in ein char[] bekommt, möglichst ohne String als Zwischenschritt. Es gibt sicher viele interessante Lösungen für andere Anwendungsfälle, aber das ist ein anderes Thema 🙂

16.806 Beiträge seit 2008
vor einem Jahr

Dein Problem basiert weiterhin auf reiner theoretischen Annahme, dass das Passwort kürzer im Speicher wäre, wenn Du ein SecureString verwendest. Dem ist weiterhin nicht so. Und ändert sich auch durch Deine Beiträge nicht.
Du betrachtest hier nämlich nur einen minimalen Zeitraum in einem System - weswegen das ganze hier ohne nennenswerten Effekt, schon gar nicht durch erhöhte Sicherheit, enden wird.

Dein Passwort wird in einer Textbox eingegeben, was ein String ist. Dieser String wird im Betriebssystem im Speicher hinterlegt und bleibt da erst mal.
Völlig egal, ob Du einen Secure String verwendest, oder nicht. Das Passwort ist dadurch nicht kürzer im Speicher.

Auch wenn Du ein Passwort in ein Array packst, ist das Passwort immer noch im Speicher.
Völlig egal, ob dieses Array durch einen String erzeugt wurde, oder durch ein SecureString.

Wenn Du Dir auch nur 1 Stunde Zeit genommen hättest zu verstehen, wie die Gesamtsituation funktioniert, hättest Dir hier locker mehrere Stunden, wildes Herumkopieren und Diskussionen sparen können.

A
764 Beiträge seit 2007
vor einem Jahr

Ja, die Diskussion ist etwas ausgeartet. 😁
Für deinen Anwendungsfall hast du ja eine gute Lösung gefunden. 👍

Mir ging es in erster Linie darum, dass niemand diesen Thread liest und dann denkt er könnte mit SecureString seine Kundendaten sichern.

Auch hier wieder die Frage, was ist konkret die bessere Alternative?

Ich kann meine Empfehlung nur nochmal wiederholen, für Security etablierte Systeme zu benutzen. Das kommt natürlich drauf an, wie der UseCase ist. In einer Windows-Domain würde man also ActiveDirectory verwenden, im Web einen passenden Anbieter.

Viele Grüsse

Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr

Dein Problem basiert weiterhin auf reiner theoretischen Annahme, dass das Passwort kürzer im Speicher wäre, wenn Du ein SecureString verwendest. Dem ist weiterhin nicht so. Und ändert sich auch durch Deine Beiträge nicht.
Du betrachtest hier nämlich nur einen minimalen Zeitraum in einem System - weswegen das ganze hier ohne nennenswerten Effekt, schon gar nicht durch erhöhte Sicherheit, enden wird.
Dein Passwort wird in einer Textbox eingegeben, was ein String ist. Dieser String wird im Betriebssystem im Speicher hinterlegt und bleibt da erst mal.

Nö. Ich habe mir die Implementierung von PasswordBox angesehen, mit dem ILSpy. Das Passwort wird intern so oder so in einem SecureString gehalten.

Die Getter-Methode für das Property "Passwort" wandelt den intern verwendeten SecureString in einen "normalen" String um.

Die Getter-Methode für das Property "SecurePasswort" hingegen liefert direkt einen Clone des intern verwendeten SecureString zurück, ohne Zwischenschritt.

Das Betriebssystem hat damit nur in sofern etwas damit zu tun, dass es natürlich die einzelnen KeyPress-Events an die Anwendung schickt.

Die Implementierung von PasswordBox benutzt soweit ich sehe SecureString.InsertAt() um jedes eingegebene Zeichen direkt in den internen SecureString einzufügen.

Man kann das auch leicht nachprüfen:
*Passwort in die PasswordBox eingeben und anschließen ein Memory-Dump der Anwendung erzeugen ⇒ Volltextsuche findet nichts verdächtiges *Nun das Passwort aus der PasswordBox einmal per Property "Passwort" als String abrufen, dann neues Memory-Dump erzeugen ⇒ Volltextsuche beweist, dass das Passwort jetzt als Klartext im Speicher liegt

Hinweis: Man muss mit einem Tool den Dump durchsuchen, das auch UTF-16 Strings findet. Die meisten Tools finden nur ASCII, Latin-1 oder evtl. noch UTF-8 kodierte Strings.

16.806 Beiträge seit 2008
vor einem Jahr

Nö. Ich habe mir die Implementierung von PasswordBox angesehen, mit dem ILSpy. Das Passwort wird intern so oder so in einem SecureString gehalten.

Es is leider super anstrengend, aber muss Dich leider erneut darauf Hinweisen einfach mal die Antworten vielleicht noch ganz ganz arg langsam zu lesen.

Dein Passwort wird in einer Textbox eingegeben, was ein String ist. Dieser String wird im Betriebssystem im Speicher hinterlegt und bleibt da erst mal.
Völlig egal, ob Du einen Secure String verwendest, oder nicht. Das Passwort ist dadurch nicht kürzer im Speicher.

Und genau das sieht man auch im Quellcode der PasswortBox.


 [SecurityCritical]
            set
            {
                if (value == null)
                {
                    value = String.Empty;
                }
 
                using (SecureString securePassword = new SecureString())
                {
                    #pragma warning suppress 6506 // value is set to String.Empty if it was null.
                    for (int i = 0; i < value.Length; i++)
                    {
                        securePassword.AppendChar(value[i]);
                    }
 
                    SetSecurePassword(securePassword);
                }
            }

Es ist ein String, der als Value der Property übergeben wird, und dann in einer PasswortBox landet. Das Backing Field ist SecureString in dem Zusammenhang irrelevant ist, weil der String selbst bleibt. Es ist nicht möglich einen Wert hier ohne ein String als Übertragungsmedium zu setzen.
Egal ob Du einen SecureString verwendest oder nicht - das Passwort landet immer zuerst in einem String.

Wirkliche Bitte: les Dir doch zumindest das eigene Zeug durch, das Du als Referenz nennst, bevor Du Halbwahrheiten schreibst.
Das Zeug hier lesen auch andere Leute im Internet.

4.931 Beiträge seit 2008
vor einem Jahr

Hallo Abt,

das stimmt so nicht, diese Eigenschaft Password wird direkt nicht von der PasswordBox benutzt - und sollte eigentlich auch nicht vom Anwendercode, steht ja auch in den Kommentaren dazu:


/// Use the SecurePassword property in place of this one when possible.
/// Doing so reduces the risk of revealing content that should be kept secret.

Intern wird die Klasse PasswordTextContainer, welche einen SecureString-Member enthält, benutzt.
Und bei der Anzeige wird ja auch nur jeweils das PasswordChar (d.h. standardmäßig ein \*) angezeigt, so daß dieser String niemals das eigentliche Passworrt enthält.

PS: Ich habe schon die ganze Zeit dieses Thema interessiert verfolgt.
Und ich finde es legitim von Weressated, diesen Weg bei diesem konkreten Problem zu gehen (nämlich Eingabe eines Passworts vom Benutzer und Übertragung an eine externe Crypto-Library und dabei dann keine, bzw. nur temporäre, Speicherspuren zu hinterlassen).

16.806 Beiträge seit 2008
vor einem Jahr

das stimmt so nicht, diese Eigenschaft Password wird direkt nicht von der PasswordBox benutzt

Ja und nein. Es kommt drauf an was Du bindest.

Und ich finde es legitim von Weressated, diesen Weg bei diesem konkreten Problem zu gehen (nämlich Eingabe eines Passworts vom Benutzer und Übertragung an eine externe Crypto-Library und dabei dann keine, bzw. nur temporäre, Speicherspuren zu hinterlassen).

Klar ist der Wunsch danach legitim, keine Frage - der Weg ist halt seit 10 Jahren obsolete, was selbst die Security Architekten hinter SecureString nicht zum Spaß sagen oder um Leute zu ärgern. Hat ja seinen Grund, wieso man damit durch zertifizierte Security Audits fliegt, nich? Oder haben die alle unrecht? 🙂

Die Kaltstartattacke - also Hardware - mit dem Speichermanagement von Windows zu vergleichen; auch wie Äpfel und Birnen.
Verweise nun glaub zum 8. Mal auf die Vorträge von Berry, in denen er die Lücken aufzeigt, dass in der Realität SecureString nichts sicherer macht.

4.931 Beiträge seit 2008
vor einem Jahr

Dann lies aber auch die beiden Kommentare ab jozefizso commented on Aug 18, 2019 in Obsolete the SecureString type und genau darum geht es in diesem Thema hier...

Oder hast du einen anderen, sicheren Weg, wie man ein Passwort eines Benutzers weiterreicht, z.B. zum Verschlüsseln einer Archivdatei (z.B. ZIP oder RAR)?
Bei einem Internet-Browser möchtest du ja auch nicht, daß das von dir eingegebene Passwort (z.B. hier für das Forum oder zu deiner Bank) bei einem möglichen Crash im Dump auftaucht.

16.806 Beiträge seit 2008
vor einem Jahr

Das ist der perfekte Thread, der zeigt, dass die Leute SecureString missverstehen - und bestätigt ja meine Aussage. Danke dafür 🙂

Yes, for example the PasswordBox control returns password as SecureString. This prevents the password from being written out to log files and it’s required to work with some native Win32 authentication API.

  • Dass nicht geloggt wird, liegt am Logging nicht am Type - und auch nur bei gewissen Logging Frameworks
  • SecureString ist eine .NET Implementierung, nicht Windows. Es gibt nicht eine einzige Win32 API, die SecureString erfordert.

Dazu auch Berry's Antwort:

I admit I am a little confused when you mention Win32. Windows has no idea about securestrings, they're purely a .NET concept.

Und dann wird weiter auf ein Doc verwiesen, das keine Win32 ist, was ebenfalls beantwortet wird.

Der Aussage

They will create their own crypto so applications will be even more insecure.

gebe ich ebenfalls absolut Recht. Und das wird ja bereits auch angegangen.

Levi Broderick antwortet ja recht deutlich mit

Nobody is telling developers to implement their own approach to encryption, and nobody is giving up on security. In fact, the proposed replacement (see dotnet/coreclr/issues/18386) clears out memory more aggressively and prevents secrets leakage better than SecureString ever did. It's a way to move the entire platform forward while leaving behind types like SecureString which were never able to live up to their promise.

Aber wir drehen uns im Kreis.

125 Beiträge seit 2023
vor einem Jahr

Ich möchte hier auch mal mit mischen.

Schauen wir uns doch mal 2 mögliche Angriffsvektoren an und wie die PasswordBox bzw. der darin gekapselte SecureString da schützen.*Keylogger
NEIN, kein Schutz, denn die Information wird abgegriffen bevor diese den SecureString überhaupt erreicht

*Speicher auslesen
JEIN, nur bedingt, denn irgendwann muss man die Hosen runterlassen und das Password muss in Klartext (als string oder char[]) an die entsprechende Authentifizierungs-Logik übergeben werden und dann ist das Kennwort wieder abgreifbar (je nach Umsetzung für eine kurze oder sehr lange Zeitspanne)

Wenn man sich also auf den SecureString verlässt, dann hat man lediglich die Script-Kiddies ausgesperrt, die mal eben so im Speicher nach Passwörtern Ausschau halten und dann aufgeben, wenn sie da nichts finden. Für alle anderen - die auf wirklichen Schaden aus sind - stellt das keine ernst zu nehmende Hürde dar und ist damit gleichbedeutend wie gar kein Schutz.

Die Lösung dafür liegt eher im Anmelde-Konzept, wie z.B.*Anmeldung mit 2FA *Passwortlose Anmeldung (wie z.B. die Anmeldung bei Office 365 mit der MS Authenticator APP)

Dort spielt es keine Rolle, ob das Kennwort erbeutet wird, bzw. es gibt einfach keins zu erbeuten.

Hat die Blume einen Knick, war der Schmetterling zu dick.

4.931 Beiträge seit 2008
vor einem Jahr

Es geht in dem Eingangsbeitrag nicht um eine Anmeldung, sondern um ein Passwort für eine Verschlüsselung (vllt. sollte man es daher besser einfach Crypto-Key nennen)...

Wie Weressated geschrieben hat, geht es um Bouncy Castle.

Edit: Um es sich besser vorzustellen, wie dort als Beispiel verlinkt: kpbe (nur eben direkt per Library angesprochen, anstatt als Kommandozeilen-Tool).

2.078 Beiträge seit 2012
vor einem Jahr

Ich finde aber die Formulierung von BlonderHans ganz passend:

Wenn man sich also auf den SecureString verlässt, dann hat man lediglich die Script-Kiddies ausgesperrt, die mal eben so im Speicher nach Passwörtern Ausschau halten und dann aufgeben, wenn sie da nichts finden. Für alle anderen - die auf wirklichen Schaden aus sind - stellt das keine ernst zu nehmende Hürde dar und ist damit gleichbedeutend wie gar kein Schutz.

Ich denke, das beschreibt es ganz gut.

Wenn man nun in der Situation ist, ein Passwort (oder einen Crypto-Key) abfragen zu wollen, dann kann man das entweder akzeptieren, oder man überlegt sich ein gänzlich anderes Konzept, was ohne Passwort/Crypto-Key auskommen kann.
Wenn man aber bei der Eingabe bleiben will/muss, dann hat man keine andere Wahl und hat Stand jetzt (?) nur den blanken String oder den "Secure"String zur Auswahl.

Demnach finde ich den SecureString nicht pauschal falsch, in solchen Situationen würde ich ihn auch weiterhin nutzen.
Nur sollte man wissen, dass man damit nicht mehr erreicht, als die Skript-Kiddies auszusperren, was aber immer noch mehr (quasi "sicherer") ist, als der blanke String.

Weressated Themenstarter:in
28 Beiträge seit 2023
vor einem Jahr

en werden und dann ist das Kennwort wieder abgreifbar (je nach Umsetzung für eine kurze oder sehr lange Zeitspanne)[/list]
Wenn man sich also auf den SecureString verlässt, dann hat man lediglich die Script-Kiddies ausgesperrt, die mal eben so im Speicher nach Passwörtern Ausschau halten und dann aufgeben, wenn sie da nichts finden. Für alle anderen - die auf wirklichen Schaden aus sind - stellt das keine ernst zu nehmende Hürde dar und ist damit gleichbedeutend wie gar kein Schutz.

Du argumentierst hier schon wieder gegen eine vermeintliche "perfekte" Sicherheit, die hier niemals auch nur ansatzweise behauptet wurde. Das nennt man Strohmann-Argument 😉

Dass ein SecureString keine "perfekte" Sicherheit gegen alle denkbaren Angriffe bietet, wurde nie bestritten. Dass ein SecureString niemals weniger sicher als ein "normaler" String ist, sondern im Gegenteil gegen bestimmte Angriffe schützt (bzw. diese deutlich erschwert) ist aber ebenfalls unstrittig. Dabei geht es übrigens keines Wegs nur (aber auch) darum, dass ein lokaler Angreifer den Speicher Deines Prozesses auslesen könnte. Sensible Daten, die länger als unbedingt nötig als Klartext im Speicher liegen, können auch schnell mal in Crash-Dumps, in der Auslagerungsdatei, o.ä. landen. Oder denke mal an prominente Sicherheitslücken wie "Heartbleed", wo ein Remote-Angreifer einfach mal aufgrund eines Bugs ganze Teile des Arbeitsspeichers aus der Ferne auslesen konnte. Da willst Du dann lieber nichts sensibles als Klartext drin rumliegen haben. Da der Angreifer pro Request nur wenige Daten auf einmal ausspähen konnte, das aber beliebig oft immer wieder tun konnte, kam es also ganz entscheidend darauf an, wie lange die "kritischen" Daten im Arbeitsspeicher lagen. Die Erfahrung lehrt: Solche oder ähnliche Sicherheitslücken können und werden immer wieder auftreten, egal wie viel man Testet. Um so wichtiger ist es, proaktiv entsprechende Maßnahme vorzusehen, die den Schaden im Fall der Fälle eindämmen.

Dass ein "nicht perfekter" Schutz gleichbedeutend mit "gar keine" Schutz sein soll, ist also nach wie vor Schwarz-Weiß-Denken, das hier überhaupt nicht weiter hilft. Du wirst in der Realität niemals eine "perfekten" Schutz gegen alle denkbaren Angriffe haben können. Schon gar nicht durch eine einzelne Maßnahme. Das ist doch aber keine Ausrede dafür, bereits vorhandene Sicherheitsmechanismen nicht zu nutzen! Sicherheit ist immer eine Kombination aus vielen Einzelmaßnahmen. Es geht immer darum bekannte Angriffe entweder unmöglich oder zumindest deutlich schwieriger zu machen. Nach Deiner Argumentation wären auch Sicherheitsmaßnahmen wie DEP oder ASLR komplett sinnlos, weil diese ebenfalls mit bekannten Angriffs-Techniken (Spraying, Return-to-libc-Attack, etc.) doch wieder umgangen werden können. Trotzdem sind Techniken wie DEP und ASLR sehr wohl nützlich, eben weil sich bestimmte Sicherheitslücken, die in der Praxis des öfteren vorkommen, damit deutlich schwerer ausnutzen lassen.

Konkret: Eine PasswordBox verwendet intern sowieso einen SecureString, um die Benutzer-Eingabe zu halten – wie bereits zuvor erwähnt. Das Passwort kannst Du über die entsprechenden Properties wahlweise als SecureString oder als String von der PasswordBox bekommen – wobei in letzterem Fall einfach die get-Methode den intern verwendeten SecureString in einen "nicht-secure" String raus kopiert, womit das Passwort dann unmittelbar und auf unbestimmte Zeit als Klartext im Speicher landet. Was ist jetzt bitte der konkrete Grund bzw. Vorteil, wieso man hier das Passwort besser als String anstatt naheliegenderweise als SecureString entgegen nehmen sollte 🤔

Die Lösung dafür liegt eher im Anmelde-Konzept, wie z.B.
Anmeldung mit 2FA

Passwortlose Anmeldung (wie z.B. die Anmeldung bei Office 365 mit der MS Authenticator APP)

Dort spielt es keine Rolle, ob das Kennwort erbeutet wird, bzw. es gibt einfach keins zu erbeuten.

Letzten Endes verlagerst Du damit aber auch nur das "Problem". Denn auch die Authenticator App muss zwangsläufig das "Shared Secret", das in die HMAC-Berechnung zur Erzeugung des Anmelde-Codes einfließt, irgendwo abspeichern - und es für die Dauer der Berechnung des Anmelde-Codes zumindest temporär in den Arbeitsspeicher laden. Der Vorteil von 2FA mit Authenticator App ist eher darin zu sehen, dass das "Shared Secret" selbst - im Unterschied zu einem Passwort - niemals irgendwo eingegeben oder übermittelt werden muss (nachdem man es initial einmalig in die Authenticator App geladen hat). Stattdessen werden immer nur Anmelde-Codes mit kurzer Gültigkeitsdauer eingegeben bzw. übermittelt, was "Phishing" Angriffe quasi unmöglich bzw. sinnfrei macht. Ein weiterer Punkt ist natürlich auch, dass die Authenticator App typischerweise auf einem separaten Gerät läuft und der Angreifer somit zwei Geräte kompromittieren müsste.

Aber: So interessant das Thema "Anmeldung mit 2FA" sein mag, es hat nichts mit dem hier diskutieren Anwendungsfall zu tun 😁

Es ist ein String, der als Value der Property übergeben wird, und dann in einer PasswortBox landet. Das Backing Field ist SecureString in dem Zusammenhang irrelevant ist, weil der String selbst bleibt. Es ist nicht möglich einen Wert hier ohne ein String als Übertragungsmedium zu setzen. PasswordBox hat zwar tatsächlich ein Property wo man das Passwort als "normlen" String abfragen oder sogar auch aus einem solchen setzen könnte (wie ich ja auch bereits mehrfach erwähnt habe), aber das heißt ja noch lange nicht, dass man diese Methode benutzen muss oder sollte! Der Standard-Anwendungsfall ist ja der, dass der Benutzer sein Passwort Zeichen für Zeichen in die PasswordBox eintippt - wobei das Passwort Zeichen für Zeichen (bei jedem KeyEvent) in den internen SecureString einfügt wird, ohne das jemals das komplette Passwort in einem einzigen zusammenhängen String vorliegt - und am Ende ruft man dann das vollständige Passwort über das Property "SecurePasswort" als SecureString ab.

(Und nein: Die haben es nicht maximal doof so programmiert, dass bei jedem Zeichen, das man eintippt, das Passwort als String ausgelesen, dann das Zeichen an den String angehängt und schließlich das Passwort aus dem String neu gesetzt wird 😘 )

J
641 Beiträge seit 2007
vor einem Jahr

cSharp Projekte : https://github.com/jogibear9988