Frage

Ist es möglich, "wischen" Strings in Delphi? Lassen Sie mich erklären:

Ich schreibe eine Anwendung, die ein DLL-Benutzer enthalten wird autorisieren. Es wird eine verschlüsselte Datei in einen XML-DOM, verwenden Sie die Informationen dort lesen, und dann das DOM freigeben.

Es ist offensichtlich, dass die unverschlüsselte XML immer noch in dem Speicher der DLL sitzt und daher anfällig für Prüfung. Nun, ich werde gehen, nicht über Bord dies in Schutz - der Benutzer eine andere DLL erstellen könnte - aber ich möchte Benutzernamen zu verhindern, sitzen seit Ewigkeiten im Speicher einen grundlegenden Schritt. Aber ich glaube nicht, dass ich einfach den Speicher ohnehin wegen Referenzen wischen kann. Wenn ich meinen DOM durchquere (die eine TNativeXML Klasse ist) und jede String-Instanz finden und es dann in etwas machen wie „aaaaa“, dann wird es nicht eigentlich die neuen Zeichenfolge Zeiger auf die DOM-Referenz zuweisen, und dann die alte Zeichenfolge verlassen sitzt dort im Speicher wartet Neuzuweisung? Gibt es einen Weg, um sicher zu sein, ich die einzige und ursprüngliche Kopie bin zu töten?

Oder gibt es in D2007 ein Mittel, es zu sagen, alle ungenutzten Speicher aus dem Heap wischen? So konnte ich das DOM loslassen, und dann sagen, es abzuwischen.

Oder soll ich nur mit meiner nächsten Aufgabe auf und vergessen, weil es wirklich nicht wert ist, stört.

War es hilfreich?

Lösung

Ich glaube nicht, es lohnt sich die Mühe mit, denn wenn ein Benutzer die Speicher des Prozesses lesen kann die DLL, der gleiche Benutzer auch mit der Ausführung zu einem bestimmten Zeitpunkt anhalten kann. Anhalten der Ausführung vor dem Speicher gelöscht wird, wird immer noch dem Anwender vollen Zugriff auf die unverschlüsselten Daten geben.

IMO jeder Benutzer ausreichend interessiert und in der Lage zu tun, was Sie beschreiben, nicht ernsthaft von der DLL ist sehr unpraktisch, wischen Sie den Speicher.

Andere Tipps

Zwei allgemeine Punkte dazu:

Erstens ist dies einer jener Bereiche, in denen „wenn Sie fragen müssen, sollten Sie wahrscheinlich nicht tun.“ Und nehmen Sie bitte nicht, dass die falsche Art und Weise; Ich meine keine Respektlosigkeit zu Ihren Programmierkenntnisse. Es ist nur so, dass das Schreiben sicherer, kryptografisch starke Software ist etwas, das Sie entweder ein Experte sind an oder Sie sind es nicht. Sehr viel in der gleichen Art und Weise, dass „ein wenig Karate“ ist viel gefährlicher als zu wissen, kein Karate überhaupt zu kennen. Es gibt eine Reihe von Tools von Drittanbietern für das Schreiben sicherer Software in Delphi, die zur Verfügung kompetente Unterstützung haben; Ich würde stark jemand ohne tiefe Kenntnis der Verschlüsselungsdienste in Windows, die mathematischen Grundlagen der Kryptographie und Erfahrung in dem Sieg über Seitenkanalangriff ermutigen, zu versuchen, anstatt zu verwenden, um „ihre eigene Rolle.“

Ihre Frage zu beantworten: Der Windows-API verfügt über eine Reihe von Funktionen, die nützlich sind, wie zum Beispiel: CryptProtectMemory . Dies wird jedoch ein falsches Gefühl der Sicherheit bringen, wenn Sie Ihr Gedächtnis verschlüsseln, aber ein Loch an anderer Stelle im System, oder einen Seitenkanal aus. Es kann wie sein ein Schloss an der Tür setzen, aber verlassen Sie das Fenster geöffnet.

Wie wäre es so etwas wie das?

procedure WipeString(const str: String);
var
  i:Integer;
  iSize:Integer;
  pData:PChar;

begin
    iSize := Length(str);
    pData := PChar(str);

    for i := 0 to 7 do
    begin
      ZeroMemory(pData, iSize);
      FillMemory(pData, iSize, $FF); // 1111 1111
      FillMemory(pData, iSize, $AA); // 1010 1010
      FillMemory(pData, iSize, $55); // 0101 0101
      ZeroMemory(pData, iSize);
    end;
end;

DLLs besitzen nicht zugewiesenen Speicher, Prozesse zu tun. Der Speicher von Ihrem spezifischen Prozess zugewiesen wird einmal verworfen werden endet der Prozess, ob die DLL rumhängt (weil es bei der Verwendung von einem anderen Prozess ist) oder nicht.

Wie wäre es, die Datei in einen Stream zu entschlüsseln, einen SAX-Prozessor statt eines XML-DOM mit Ihrer Prüfung zu tun und dann den entschlüsselten Strom überschrieben wird, bevor es zu befreien?

Wenn Sie den FastMM Speichermanager in Full Debug-Modus verwenden, dann können Sie es zwingen Speicher zu überschreiben, wenn es freigegeben wird.

Normalerweise wird das Verhalten zu erkennen wilde Zeiger verwendet, aber es kann auch für das, was Ihr wollen verwendet werden.

Auf der anderen Seite, stellen Sie sicher, dass Sie verstehen, was Craig Stuntz schreibt:. Nicht schreiben diese Authentifizierung und Autorisierung Sachen selbst, das zugrunde liegende Betriebssystem verwenden, wenn möglich

BTW: Hallvard Vassbotn einen schönen Blog über FastMM schrieb: http://hallvards.blogspot.com/2007/ 05 / Einsatz-full-FastMM denken-donating.html

Grüße,

Jeroen Pluimers

Unordentlich, aber man könnte eine Notiz von der Heap-Größe, die Sie verwendet haben, während Sie den Heap mit sensiblen Daten gefüllt haben dann, wenn dieser freigegeben wird, kann ein GetMem Sie einen großen Teil zuzuteilen Spanning (sagen wir) 200% davon. tut einen Fill auf diesem Brocken und die Annahme, dass jede Fragmentierung unlinkely viel nützt einen Prüfer zu sein. Bri

Wie sei es das Passwort als Hash-Wert in der XML zu halten und verifizieren, indem die Hash-Wert des eingegebenen Passwortes mit dem Hash-Passwort in Ihrem XML-Vergleich.

Edit:. Sie können verschlüsselt alle sensiblen Daten halten und erst im letzten möglichen Moment entschlüsseln

Wäre es möglich, die entschlüsselte XML in ein Array von char oder Byte anstelle einer Zeichenfolge zu laden? Dann gäbe es kein Copy-on-write Handhabung, so würden Sie in der Lage sein, den Speicher mit # 0 der Verfüllung vor befreien?

Seien Sie vorsichtig, wenn Array von char Zeichenfolge zuweisen, wie Delphi einige intelligente Handhabung hier für die Kompatibilität mit herkömmlichen gepackten Array [1..x] Saiblings hat.

Auch könnten Sie verwenden Short?

Wenn Ihre Verwendung von XML, auch verschlüsselt zu speichern Passwörter Putten Benutzer gefährdet. Ein besserer Ansatz wäre es, die Hash-Werte der Passwörter zu speichern statt, und dann den Hash gegen das eingegebene Passwort vergleichen. Der Vorteil dieses Ansatzes besteht darin, dass auch den Hash-Wert zu wissen, werden Sie nicht das Passwort kennen, die den Hash macht. Hinzufügen eine Brute-Force-Kennung (ungültige Anmeldeversuche zählen, und sperrt das Konto nach einer bestimmten Anzahl) wird die Sicherheit noch weiter erhöhen.

Es gibt mehrere Methoden, die Sie verwenden können, einen Hash einer Zeichenfolge zu erstellen. Ein guter Ausgangspunkt wäre bei dem Turbo-Power Open-Source-Projekt suchen „ LockBox “, ich glaube, es hat mehrere Beispiele für einen Weg Hash-Schlüssel erzeugt wird.

Bearbeiten

Wie aber zu wissen, den Hash-Wert, wenn seine ein Weg, um Hilfe? Wenn Ihr wirklich paranoid, können Sie den Hash-Wert von etwas ändern prediticable dass nur würden Sie wissen, ... sagen wir, eine Zufallszahl einen bestimmten Startwert plus dem Datum. Sie könnten dann speichern nur genug von der Hash in Ihrem XML, so dass Sie es als Ausgangspunkt für den Vergleich verwenden können. Die nette Sache über psuedo Zufallszahlen-Generatoren ist, dass sie die gleiche Serie von „random“ Zahlen immer erzeugen die gleiche Samen gegeben.

Seien Sie von Funktionen vorsichtig, die versuchen, eine Zeichenfolge als Zeiger zu behandeln und versuchen FillChar oder ZeroMemory zu verwenden, um die Zeichenfolge Inhalt zu löschen.

  • ist dies beide falsch (Strings geteilt, du bist Einschrauben jemand anderes, der derzeit die Zeichenfolge ist mit)
  • und kann eine Zugriffsverletzung verursachen (wenn die Zeichenfolge eine Konstante gewesen passieren, ist es auf einer schreibgeschützten Datenseite in dem Prozessadressraum sitzt, und zu versuchen, es wird eine Zugriffsverletzung zu schreiben)

procedure BurnString(var s: UnicodeString);
begin
    {
        If the string is actually constant (reference count of -1), then any attempt to burn it will be
        an access violation; as the memory is sitting in a read-only data page.

        But Delphi provides no supported way to get the reference count of a string.

        It's also an issue if someone else is currently using the string (i.e. Reference Count > 1).
        If the string were only referenced by the caller (with a reference count of 1), then
        our function here, which received the string through a var reference would also have the string with
        a reference count of one.

        Either way, we can only burn the string if there's no other reference.

        The use of UniqueString, while counter-intuitiave, is the best approach.
        If you pass an unencrypted password to BurnString as a var parameter, and there were another reference,
        the string would still contain the password on exit. You can argue that what's the point of making a *copy*
        of a string only to burn the copy. Two things:

            - if you're debugging it, the string you passed will now be burned (i.e. your local variable will be empty)
            - most of the time the RefCount will be 1. When RefCount is one, UniqueString does nothing, so we *are* burning
                the only string
    }
    if Length(s) > 0 then
    begin
        System.UniqueString(s); //ensure the passed in string has a reference count of one
        ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar));

        {
            By not calling UniqueString, we only save on a memory allocation and wipe if RefCnt <> 1
            It's an unsafe micro-optimization because we're using undocumented offsets to reference counts.

            And i'm really uncomfortable using it because it really is undocumented.
            It is absolutely a given that it won't change. And we'd have stopping using Delphi long before
            it changes. But i just can't do it.
        }
        //if PLongInt(PByte(S) - 8)^ = 1 then //RefCnt=1
        //  ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar));

        s := ''; //We want the callee to see their passed string come back as empty (even if it was shared with other variables)
    end;
end;

Wenn Sie die UnicodeString Version haben, können Sie die AnsiString und WideString Versionen erstellen:

procedure BurnString(var s: AnsiString); overload;
begin
    if Length(s) > 0 then
    begin
        System.UniqueString(s);
        ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar));

        //if PLongInt(PByte(S) - 8)^ = 1 then //RefCount=1
        //  ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar));

        s := '';
    end;
end;

procedure BurnString(var s: WideString);
begin
    //WideStrings (i.e. COM BSTRs) are not reference counted, but they are modifiable
    if Length(s) > 0 then
    begin
        ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar));

        //if PLongInt(PByte(S) - 8)^ = 1 then //RefCount=1
        //  ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar));

        s := '';
    end;
end;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top