Frage:
Wäre es eine gute sichere Programmierpraxis, eine "sensible" Variable vor dem Löschen zu überschreiben?
Jonathan
2014-12-04 22:18:15 UTC
view on stackexchange narkive permalink

Ist es eine gute sichere Programmierpraxis, vertrauliche Daten, die in einer Variablen gespeichert sind, zu überschreiben, bevor sie gelöscht werden (oder den Gültigkeitsbereich verlassen)? Meiner Meinung nach würde dies verhindern, dass ein Hacker aufgrund von Datenremanenz latente Daten im RAM lesen kann. Würde es eine zusätzliche Sicherheit geben, wenn Sie es mehrmals überschreiben? Hier ist ein kleines Beispiel für das, worüber ich in C ++ spreche (mit Kommentaren).

  void doSecret () {// Das Geheimnis, das Sie schützen möchten (wahrscheinlich am besten, wenn Sie es nicht haben so fest codiert) int mySecret = 12345; // Mach was auch immer du mit der Zahl machst ... // ** Lösche den Speicher von mySecret, indem du darüber schreibst ** mySecret = 111111; mySecret = 0; // Vielleicht ein paar Mal in einer Schleife wiederholen}  

Ein Gedanke ist, wenn dies tatsächlich die Sicherheit erhöht, wäre es schön, wenn der Compiler die Anweisungen dazu automatisch hinzufügen würde (vielleicht von Standard oder oder indem Sie den Compiler anweisen, dies beim Löschen von Variablen zu tun.


Diese Frage wurde als Informationssicherheitsfrage der Woche a aufgeführt > .
Lesen Sie den Blogeintrag vom 12. Dezember 2014 , um weitere Informationen zu erhalten, oder senden Sie Ihre eigene Frage der Woche .

Siehe auch: [Ansicht auf Betriebssystemebene] (http://security.stackexchange.com/questions/74288/is-data-remanence-a-concern-in-ram)
Beachten Sie, dass dies je nach [Sprache] [schwierig] sein kann (http://stackoverflow.com/questions/3785366/how-to-ensure-that-compiler-optimizations-dont-introduce-a-security-risk). http://stackoverflow.com/questions/3785582/how-to-write-a-password-safe-class). (Siehe die beiden verknüpften Fragen und insbesondere ihre Antworten)
Beachten Sie auch, dass Zeichenfolgen in Java unveränderlich sind, sodass das Überschreiben (Zuweisen eines neuen Werts zur Referenzvariablen) keine Auswirkungen hat.
Dies ist nicht nur eine gute Idee, sondern Sie können auch den Speicher "sperren" (um sicherzustellen, dass er nicht zum Auslagern geschrieben wurde) und die Seite "schützen", damit sie schreibgeschützt ist, sobald die geheimen Daten vorliegen initialisiert (möglicherweise auch, um die Seite * überhaupt * als nicht zugänglich zu markieren, außer in den kleinen Fenstern, in denen Sie darauf zugreifen möchten), um einen "kanarischen" Wert unmittelbar nach dem Geheimnis in den Speicher zu schreiben, um während des Deallocs zu erkennen, ob dies der Fall ist wurde durch einen Überlauf überschrieben und um SEGV zusätzliche nicht zugängliche Schutzseiten vor und nach dem Geheimnis für Überlauf und Unterlauf zuzuweisen.
Siehe libsodiums [`Natrium_Malloc`] (https://github.com/jedisct1/libsodium/blob/master/src/libsodium/sodium/utils.c#L392) als Implementierung davon.
@rkosegi Deshalb sollte man für Schlüssel Byte [] und nicht String verwenden.
Dem C / C ++ - Compiler steht es tatsächlich frei, Ihre Überschreibungen zu optimieren, es sei denn, Sie haben Ihre Variable als "flüchtig" deklariert, da sie das Ergebnis der Ausführung des Codes nicht ändern (der Wert wird nirgendwo verwendet).
Die Nullisierung ist für NISTs [FIPS 140-2] (http://csrc.nist.gov/groups/STM/cmvp/standards.html) erforderlich, selbst bei Validierungen der Stufe 1. Angreifer nutzen den Speicher und müssen nicht lokal sein. Wir wissen zum Beispiel, dass [die NSA Windows-Fehlerberichte in ihrem XKeyscore-System protokolliert, um nicht autorisierten Zugriff zu erhalten] (http://en.wikipedia.org/wiki/Tailored_Access_Operations).
Während die meisten Antworten den Vorteil des Überschreibens der Daten (wenn möglich) erwähnen, kann ich den Vorteil des Überschreibens "einige Male in einer Schleife" nicht sehen, wie in der Frage vorgeschlagen, aber von der aktuellen Reihe von Antworten AFAICS nicht berührt. Wenn diese Daten nicht auf ein magnetisches Medium geschrieben werden und der Angreifer nur geringen Zugriff auf das System hat, hätte ich gedacht, dass ein einmaliges Überschreiben ausreichen sollte. Oder sind mehrere Schreibvorgänge immer noch von Vorteil?
Zehn antworten:
goodguys_activate
2014-12-04 22:26:55 UTC
view on stackexchange narkive permalink

Ja, das ist eine gute Idee, um den Wert zu überschreiben und dann zu löschen / freizugeben. Gehen Sie nicht davon aus, dass Sie nur die Daten "überschreiben" oder für den GC außer Reichweite lassen müssen, da jede Sprache anders mit der Hardware interagiert.

Beim Sichern einer Variablen müssen Sie möglicherweise Folgendes berücksichtigen:

  • Verschlüsselung (bei Speicherabbildern oder Seiten-Caching)
  • Fixieren im Speicher
  • Fähigkeit, als schreibgeschützt zu markieren (um weitere Änderungen zu verhindern)
  • sichere Konstruktion, indem NICHT zugelassen wird, dass eine konstante Zeichenfolge in
  • optimierenden Compilern übergeben wird (siehe Hinweis im verlinkten Artikel zu: ZeroMemory-Makro)

Die tatsächliche Implementierung des "Löschens" hängt von der Sprache und der Plattform ab. Erforschen Sie die Sprache, die Sie verwenden, und prüfen Sie, ob es möglich ist, sicher zu codieren.

Warum ist dies eine gute Idee? Crashdumps und alles, was den Heap enthält, kann Ihre sensiblen Daten enthalten. Verwenden Sie beim Sichern Ihrer In-Memory-Daten Folgendes:

Anleitungen zur Implementierung pro Sprache finden Sie in StackOverflow.

Sie sollten sich dessen bewusst sein, auch wenn Sie den Hersteller verwenden Anleitung (in diesem Fall MSFT) Es ist weiterhin möglich, den Inhalt von SecureString zu sichern und möglicherweise spezifische Verwendungsrichtlinien für Hochsicherheitsszenarien zu verwenden.

Bei der Frage ging es darum, zuerst zu überschreiben und dann zu löschen. Können Sie Ihrer Antwort etwas hinzufügen?
Es ist jedoch auch möglich, den Inhalt des Speicherplatzes eines Programms während seines Betriebs anzuzeigen. Durch das Löschen des Speichers wird lediglich der Zeiger auf den Speicher entfernt (ähnlich wie beim Löschen einer Datei der Dateizeiger auf die Datei aus dem Dateisystem entfernt wird). Durch Überschreiben wird der Speicher "sicher".
Angenommen, das Überschreiben überschreibt es tatsächlich und bewegt den Zeiger nicht nur auf einen neuen Speicherabschnitt mit den neuen Werten (was bedeutet, dass die alten Daten so lange erhalten bleiben, bis der Speicher wiederverwendet wird, genau wie beim Löschen).
@lawtonfogle-Zeiger sind normalerweise Speicheradressen, sodass alle Daten, die Sie über den Zeiger schreiben, in diesen Adressraum gelangen. Das ist allerdings eine interessante Idee. Ihre unten beschriebene Methode entspricht nicht ganz der Verwendung eines Zeigers.
@Desthro: Sofern Sie nicht im realen Modus arbeiten (d. H. Einen Betriebssystemkern schreiben), sind Zeiger normalerweise nur virtuelle Speicheradressen. Nur der Kernel hat Zugriff auf echte Speicheradressen. Es ist sicherlich möglich, dass das Betriebssystem die beiden Speicherseiten an eine andere reale Adresse verschiebt, wenn der Speicher überschrieben wird. Dies kann ohne Änderung der virtuellen Adresse erfolgen. Dies geschieht zum Beispiel beim Tauschen.
@LieRyan zeigt, wie alt meine Programmierkenntnisse sind;)
Ich denke, Sie möchten auf jeden Fall, dass das flüchtige Schlüsselwort sicherstellt, dass das, was passiert, tatsächlich überschrieben wird
@raptortech97 stellt "volatile" das tatsächlich sicher? Angenommen, ein Prozess wird angehalten und sein Speicher ausgelagert, bevor die vertrauliche Variable überschrieben werden kann. Anschließend wird er fortgesetzt. Es gibt keine Garantie dafür, dass der virtuelle Speicher wieder in denselben Bereich des physischen Speichers zurückgespeichert wird. In einem solchen Fall garantiert "flüchtig" kein Überschreiben. Ich denke. Ich bin mir aber ehrlich gesagt nicht sicher. (`volatile` verhindert bestimmte Compiler-Optimierungen, das verstehe ich, aber es schien, als ob Sie sagten, dass es mehr als das tut)
Ich habe das Gefühl, dass wir in diesen Kommentaren festgestellt haben, dass Computer schwer zu "überlisten" sind.
Lawtonfogle
2014-12-04 22:45:14 UTC
view on stackexchange narkive permalink

Einen Wert speichern, der nicht wieder verwendet wird? Scheint etwas zu sein, das optimiert werden würde, unabhängig von den möglichen Vorteilen.

Außerdem können Sie die Daten im Speicher möglicherweise nicht überschreiben, je nachdem, wie die Sprache selbst funktioniert. In einer Sprache, in der beispielsweise ein Garbage Collector verwendet wird, wird dieser nicht sofort entfernt (und dies setzt voraus, dass Sie keine anderen Referenzen hängen gelassen haben).

Zum Beispiel in C #, glaube ich Folgendes funktioniert nicht.

  string secret = "meine geheimen Daten"; ... viel Arbeit ... string secret = "blahblahblah";  

"meine geheimen Daten" hängt herum, bis Müll gesammelt wird, weil er unveränderlich ist. Diese letzte Zeile erstellt tatsächlich eine neue Zeichenfolge und hat einen geheimen Punkt darauf. Es beschleunigt nicht, wie schnell die tatsächlichen geheimen Daten entfernt werden.

Gibt es einen Vorteil? Angenommen, wir schreiben es in Assembler oder einer Sprache mit niedrigem Hebel, damit wir sicherstellen können, dass wir die Daten überschreiben, und wir schalten unseren Computer in den Ruhezustand oder lassen ihn bei laufender Anwendung eingeschaltet, und unser RAM wird von einem bösen Dienstmädchen abgekratzt Das böse Mädchen hat unsere RAM-Daten erhalten, nachdem das Geheimnis überschrieben wurde, aber bevor es gerade gelöscht worden wäre (wahrscheinlich ein sehr kleiner Speicherplatz), und nichts anderes im RAM oder auf der Festplatte würde dieses Geheimnis preisgeben ... dann sehe ich eine mögliche Zunahme in Bezug auf Sicherheit.

Aber die Kosten im Vergleich zum Nutzen scheinen diese Sicherheitsoptimierung auf unserer Liste der Optimierungen sehr niedrig zu machen (und unter dem Punkt "lohnenswert" für die meisten Anwendungen im Allgemeinen).

Ich könnte möglicherweise eine begrenzte Verwendung in speziellen Chips sehen, die Geheimnisse für kurze Zeit aufbewahren sollen, um sicherzustellen, dass sie für die kürzest mögliche Zeit aufbewahrt werden, aber selbst dann bin ich mir nicht sicher, welchen Nutzen die Kosten haben.

"wahrscheinlich ein sehr kleiner Raum" - es ist wahrscheinlich nicht so schwer, Fälle zu finden, in denen der sehr kleine Raum mindestens die verbleibende Lebensdauer des Prozesses darstellt. Das heißt, es könnte unbenutzten Speicher geben, der aus verschiedenen Gründen (und ich meine nicht nur einen Speicherverlust) für eine Weile ungenutzt bleiben kann. Das böse Mädchen wird schließlich unser gesamtes Gedächtnis nach irgendetwas Nützlichem durchsuchen. Das Überschreiben an dem Punkt, an dem es nicht mehr verwendet wurde, würde daher ein Fenster schließen. Aber wie Sie sagen, wir können immer noch nicht mit einem Sicherheitsvorteil von `mySecret = 0 rechnen; mySecret = -1; `.
Wenn Sie Bedenken haben, dass die Zuordnung optimiert wird, deklarieren Sie die Variable einfach als "flüchtig" (in C / C ++). Das wird den Trick machen. Wenn der Wert eine Zeichenfolge ist, überschreiben Sie den * Inhalt * der Zeichenfolge, anstatt eine einfache Zuweisung zu verwenden.
Zahlreiche sprachabhängige Tricks, die sich nicht übertragen lassen. Alle von Ihnen verwendeten Bibliotheken, in denen geheime Daten gespeichert sind, müssen zeilenweise überprüft werden, um sicherzustellen, dass sie dies tun. Und wenn nicht, implementieren Sie die Mathematik- / Kryptobibliotheken erneut? Die Sicherheitssteigerung pro Ressourcenverbrauchsquote ist so gering und die Wahrscheinlichkeit einer Verschlechterung Ihrer Sicherheit (durch Umschreiben der Bibliothek) ist hoch genug, dass ich keinen berechtigten Anwendungsfall für den durchschnittlichen Entwickler sehe.
Cort Ammon
2014-12-06 22:45:52 UTC
view on stackexchange narkive permalink

Sie benötigen ein Bedrohungsmodell

Sie sollten erst dann über das Überschreiben von Sicherheitsvariablen nachdenken, wenn Sie ein Bedrohungsmodell haben, das beschreibt, welche Arten von Hacks Sie verhindern möchten. Sicherheit ist immer mit Kosten verbunden. In diesem Fall sind die Kosten die Entwicklungskosten, die entstehen, wenn Entwickler lernen, den gesamten zusätzlichen Code zur Sicherung der Daten zu verwalten. Diese Kosten bedeuten, dass Ihre Entwickler möglicherweise eher Fehler machen, und diese Fehler sind eher die Ursache für ein Leck als ein Speicherproblem.

  • Kann Der Angreifer greift auf Ihr Gedächtnis zu? Wenn ja, gibt es einen Grund, warum Sie glauben, sie könnten / würden den Wert nicht einfach riechen, bevor Sie ihn überschreiben? Welche Zeiträume hat der Angreifer Zugriff auf Ihren Speicher?
  • Kann der Angreifer auf Core-Dumps zugreifen? Stört es Sie, wenn sie auf vertrauliche Daten zugreifen können, wenn sie so laut sind, dass sie überhaupt einen Core-Dump verursachen?
  • Ist dies Open Source oder Closed Source? Wenn es sich um Open Source handelt, müssen Sie sich um mehrere Compiler kümmern, da Compiler ständig Dinge wie überschriebene Daten optimieren. Ihre Aufgabe ist es nicht, Sicherheit zu bieten. ( Für ein Beispiel aus dem wirklichen Leben verfügt Schneiers PasswordSafe über spezielle Klassen zum Schutz der unverschlüsselten Kennwortdaten. Zu diesem Zweck verwendet er Windows-API-Funktionen, um den Speicher zu sperren und zu erzwingen, dass er ordnungsgemäß überschrieben wird, anstatt den Compiler zu verwenden um es für ihn zu tun )
  • Ist dies eine Sprache, in der Müll gesammelt wird? Wissen Sie, wie Sie IHRE bestimmte Version Ihres speziellen Garbage Collectors dazu zwingen können, Ihre Daten tatsächlich zu entfernen?
  • Wie viele Versuche kann der Angreifer unternehmen, um vertrauliche Daten abzurufen, bevor Sie ihn bemerken und mit anderen Mitteln abschneiden (z. B. Firewalls)?
  • Wird dies in einer virtuellen Maschine ausgeführt? Wie sicher sind Sie sich der Sicherheit Ihres Hypervisors?
  • Hat ein Angreifer physischen Zugriff? Beispielsweise verwendet Windows gerne ein Flash-Laufwerk, um den virtuellen Speicher zwischenzuspeichern. Ein Angreifer muss lediglich Windows davon überzeugen, es auf das Flash-Laufwerk zu übertragen. Wenn das passiert, ist es WIRKLICH schwer, es loszuwerden. In der Tat so schwierig, dass es keine anerkannte Methode zum zuverlässigen Löschen von Daten von einem Flash-Laufwerk gibt.

Diese Fragen müssen beantwortet werden, bevor versucht wird, vertrauliche Daten zu überschreiben. Der Versuch, Daten zu überschreiben, ohne das Thread-Modell zu adressieren, ist ein falsches Sicherheitsgefühl.

Ein weiterer Kostenfaktor ist mehr Code und mehr Anweisungen für die Ausführung des Computers (langsamer), aber ja, ein guter Punkt, um die Bedrohung zu berücksichtigen. Ich würde denken, dass ein Hacker, der während der Ausführung des Programms auf die geheimen Daten aus dem RAM zugreift, oder sogar danach eine der größten Bedrohungen darstellt. Ich denke, es wäre schön, wenn Sie dem Compiler (oder was auch immer die von Ihnen verwendete Sprache erstellt / ausführt) mitteilen könnten, dass er die Daten auf Null setzen soll, wenn dies erledigt ist.
* "Kann der Angreifer auf Ihren Speicher zugreifen?" * - Wir wissen, dass der Angreifer den Speicher verwendet, falls verfügbar. Und es muss nicht auf dem lokalen Computer sein. Wir wissen beispielsweise, dass [die NSA die Windows-Fehlerberichterstattung in ihrem XKeyscore-System protokolliert, um nicht autorisierten Zugriff zu erhalten] (http://en.wikipedia.org/wiki/Tailored_Access_Operations). Das passiert, ob Ihr Bedrohungsmodell es enthält oder nicht :)
Ob es passiert, unterscheidet sich sehr davon, ob Sie tatsächlich versuchen möchten, etwas dagegen zu unternehmen. Um Kevin Mitnick zu zitieren: "Der einzige wirklich sichere Computer ist ein Computer, der nicht im Internet angeschlossen, ausgesteckt, in einem Betonbunker unter der Erde mit bewaffneten Wachen darüber gelagert ist, und selbst dann würde ich ab und zu nachsehen." Wenn du dein Programm wirklich sicher machen willst, brauchst du viel mehr als StackExchange, um zu helfen ;-)
Gilles 'SO- stop being evil'
2014-12-05 00:02:43 UTC
view on stackexchange narkive permalink

Ja, es ist aus Sicherheitsgründen empfehlenswert, Daten zu überschreiben, die besonders sensibel sind, wenn die Daten nicht mehr benötigt werden, dh als Teil eines Objektdestruktors (entweder ein expliziter Destruktor, der von der Sprache bereitgestellt wird, oder eine Aktion, die das Programm ausführt vor der Freigabe des Objekts). Es ist sogar empfehlenswert, Daten zu überschreiben, die an sich nicht sensibel sind, z. B. Zeigerfelder in einer nicht mehr verwendeten Datenstruktur auf Null zu setzen und Zeiger auf Null zu setzen, wenn das Objekt, auf das sie zeigen, freigegeben wird, selbst wenn Sie es wissen Sie werden dieses Feld nicht mehr verwenden.

Ein Grund dafür ist, dass die Daten durch externe Faktoren wie einen exponierten Core-Dump, ein gestohlenes Ruhezustand-Image oder einen kompromittierten Server, der einen Speicher zulässt, verloren gehen Speicherauszug laufender Prozesse usw. Physische Angriffe, bei denen ein Angreifer die RAM-Sticks extrahiert und Datenreste nutzt, sind selten ein Problem, außer bei Laptops und möglicherweise mobilen Geräten wie Telefonen (bei denen der Balken höher ist, weil der RAM gelötet ist). und selbst dann meistens nur in gezielten Szenarien. Die Remanenz überschriebener Werte ist kein Problem: Es würde sehr teure Hardware erfordern, um in einem RAM-Chip nach einer verbleibenden mikroskopischen Spannungsdifferenz zu suchen, die durch einen überschriebenen Wert beeinflusst werden könnte. Wenn Sie sich Sorgen über physische Angriffe auf den RAM machen, besteht ein größeres Problem darin, sicherzustellen, dass die Daten im RAM und nicht nur im CPU-Cache überschrieben werden. Aber auch dies ist normalerweise ein sehr geringes Problem.

Der wichtigste Grund für das Überschreiben veralteter Daten ist die Abwehr von Programmfehlern, die dazu führen, dass nicht initialisierter Speicher verwendet wird, wie z. B. das berüchtigte Heartbleed. Dies geht über sensible Daten hinaus, da das Risiko nicht auf ein Datenleck beschränkt ist: Wenn ein Softwarefehler vorliegt, der dazu führt, dass ein Zeigerfeld ohne Initialisierung dereferenziert wird, ist der Fehler sowohl weniger anfällig für Ausnutzung als auch leichter zu verfolgen, wenn Das Feld enthält alle Bits-Null, als wenn es möglicherweise auf einen gültigen, aber bedeutungslosen Speicherort verweist.

Beachten Sie, dass gute Compiler das Nullstellen optimieren, wenn sie feststellen, dass der Wert nicht mehr verwendet wird. Möglicherweise müssen Sie einen compilerspezifischen Trick verwenden, um den Compiler davon zu überzeugen, dass der Wert weiterhin verwendet wird, und so den Nullungscode zu generieren.

In vielen Sprachen mit automatischer Verwaltung können Objekte ohne in den Speicher verschoben werden beachten. Dies bedeutet, dass es schwierig ist, Lecks veralteter Daten zu kontrollieren, es sei denn, der Speichermanager selbst löscht nicht verwendeten Speicher (dies ist aus Leistungsgründen häufig nicht der Fall). Auf der positiven Seite sind externe Lecks normalerweise alles, worüber Sie sich Sorgen machen müssen, da Hochsprachen dazu neigen, die Verwendung von nicht initialisiertem Speicher auszuschließen (Vorsicht vor Funktionen zum Erstellen von Zeichenfolgen in Sprachen mit veränderlichen Zeichenfolgen).

By Übrigens habe ich oben „Null raus“ geschrieben. Sie können ein anderes Bitmuster als alle Nullen verwenden. All-Nullen haben den Vorteil, dass sie in den meisten Umgebungen ein ungültiger Zeiger sind. Ein Bitmuster, von dem Sie wissen, dass es ungültige Zeiger sind, das jedoch eindeutiger ist, kann beim Debuggen hilfreich sein.

Viele Sicherheitsstandards schreiben das Löschen vertraulicher Daten wie Schlüssel vor. Zum Beispiel erfordert der FIPS 140-2 -Standard für kryptografische Module dies auch bei der niedrigsten Sicherheitsstufe, was im Übrigen nur die Einhaltung von Funktionen und keine Widerstandsfähigkeit gegen Angriffe erfordert.

Normalerweise werden Geheimnisse nicht direkt behandelt. Es wird eine kryptografische Bibliothek verwendet (da die Implementierung eines Algorithmus, auch eines guten, schwierig ist und ein Implementierungsfehler Ihre Sicherheit unbrauchbar machen kann). Beschränkt man sich also auf Bibliotheken, die Daten nur vor dem Löschen ändern (möglicherweise wird die beste Bibliothek für den Job eliminiert)? Oder verwendet man eine Bibliothek, in der Daten bis zum Löschen herumhängen und somit den Vorteil verlieren, diese auf den eigenen Code anzuwenden?
@Lawtonfogle Kryptografische Bibliotheken werden häufig so geschrieben, dass nach der Verwendung mindestens Schlüssel gelöscht werden. Es wird von Krypto-Implementierern als gute Hygiene angesehen, und ich erwarte (obwohl ich keine festen Daten zu diesem Thema habe), dass es mit angemessenen Qualitätsmaßnahmen korreliert. Selbst wenn die Bibliothek dies nicht tut, können Sie die Speicherverwaltung der Bibliothek häufig über die Anwendung steuern.
Ich muss zugeben, es scheint, dass die Sicherheitsexperten, die Kryptobibliotheken schreiben, auch andere Sicherheitspraktiken einbeziehen würden, selbst wenn sie nicht direkt mit der Krypto selbst zusammenhängen. Aber Sie möchten sichergehen, dass es sich hoffentlich um Open Source handelt (wenn auch nur, um die kryptografische Integrität zu überprüfen).
"Wenn Sie sich Sorgen über physische Angriffe auf den RAM machen, besteht ein größeres Problem darin, sicherzustellen, dass die Daten im RAM und nicht nur im CPU-Cache überschrieben werden." - Sie können die Speicherbarriere (auf der untersten Ebene als CPU-Anweisung implementiert) erzwingen, um das Leeren des CPU-Cache in den RAM zu erzwingen. Wenn die Programmiersprache eine höhere Ebene hat, besteht eine Möglichkeit darin, ein Grundelement für die gemeinsame Nutzung von Speicher zu verwenden, z. B. Mutex (Sperren, Löschen, Entsperren), das im Rahmen der Implementierung Speicherbarrieren verwendet.
user10211
2014-12-16 18:48:16 UTC
view on stackexchange narkive permalink

Für eine (hoffentlich interessante) Ergänzung zu den restlichen Antworten unterschätzen viele Leute die Schwierigkeit, das Gedächtnis mit C richtig zu überschreiben. Ich werde stark aus Colin Percivals Blog-Post mit dem Titel " How to zero a buffer ".

Das Hauptproblem bei naiven Versuchen, Speicher in C zu überschreiben, sind Compiler-Optimierungen. Die meisten modernen Compiler sind "intelligent" genug, um zu erkennen, dass die allgemeinen Idome, die zum Überschreiben des Speichers verwendet werden, das beobachtbare Verhalten des Programms nicht ändern und wegoptimiert werden können. Leider bricht dies völlig das, was wir erreichen wollen. Einige der gängigen Tricks sind in dem oben verlinkten Blog-Beitrag beschrieben. Schlimmer noch, ein Trick, der für eine Version eines Compilers funktioniert, funktioniert möglicherweise nicht unbedingt mit einem anderen Compiler oder sogar einer anderen Version desselben Compilers. Sofern Sie keine Binärdateien nur verteilen, ist dies eine problematische Situation.

Die einzige Möglichkeit, den mir bekannten Speicher in C zuverlässig zu überschreiben, sind die memset_s Funktion. Leider ist dies nur in C11 verfügbar, sodass Programme, die für ältere Versionen von C geschrieben wurden, kein Glück haben.

Die Funktion memset_s kopiert den Wert von c (konvertiert in ein vorzeichenloses Zeichen) in jedes der Die ersten n Zeichen des Objekts, auf das s zeigt. Im Gegensatz zu memset muss jeder Aufruf von memset_s streng nach den Regeln der abstrakten Maschine ausgewertet werden, wie in 5.1.2.3 beschrieben. Das heißt, jeder Aufruf von memset_s muss davon ausgehen, dass der durch s und n angegebene Speicher in Zukunft zugänglich sein kann und daher die durch c angegebenen Werte enthalten muss.

Unfourtunt ist Colin Percival Die Meinung, dass das Überschreiben von Speicher nicht ausreicht. In einem nachfolgenden Blog-Beitrag mit dem Titel " Nullstellen von Puffern ist nicht ausreichend" heißt es in

Mit ein wenig Sorgfalt und einem kooperativen Compiler können wir einen Puffer auf Null setzen - aber das ist nicht das, was wir brauchen. Was wir tun müssen, ist, an jedem Ort, an dem sensible Daten gespeichert werden könnten, Null zu setzen. Denken Sie daran, der ganze Grund, warum wir vertrauliche Informationen im Speicher hatten, war, dass wir sie verwenden konnten. und diese Verwendung führte mit ziemlicher Sicherheit dazu, dass vertrauliche Daten auf den Stapel und in Register kopiert wurden.

Er fährt fort und gibt ein Beispiel für AES-Implementierungen unter Verwendung des AESNI-Befehlssatzes auf x86-Plattformen, bei dem Daten verloren gehen die Register.

Er behauptet, dass

es unmöglich ist, ein Kryptosystem sicher zu implementieren, das Vorwärtsgeheimnis in C bietet.

A. beunruhigende Behauptung in der Tat.

Vielen Dank für Ihre Erkenntnisse! Es wäre auf jeden Fall schön, wenn die C- und C ++ - Compiler eine Option zum Nullsetzen des Speichers enthalten würden, wenn der Gültigkeitsbereich überschritten wird (oder eine Möglichkeit, dem Compiler mitzuteilen, welche Variablen sicher gelöscht werden sollen).
Ari Trachtenberg
2014-12-05 09:37:45 UTC
view on stackexchange narkive permalink

Es ist wichtig, vertrauliche Daten sofort zu überschreiben, nachdem sie benötigt werden, da sonst:

  • die Daten bis zum Überschreiben auf dem Stapel bleiben und möglicherweise mit angezeigt werden können Ein Frame-Überlauf aufgrund einer anderen Prozedur.
  • Die Daten unterliegen einem Speicher-Scraping.

Wenn Sie sich den Quellcode für sicherheitsrelevante Anwendungen ansehen (z openssh), werden Sie feststellen, dass sensible Daten nach der Verwendung sorgfältig auf Null gesetzt werden.

Es ist auch richtig, dass Compiler versuchen könnten, das Überschreiben zu optimieren, und selbst wenn nicht, Es ist wichtig zu wissen, wie die Daten physisch gespeichert sind (z. B. wenn das Geheimnis auf einer SSD gespeichert ist, wird beim Überschreiben möglicherweise der alte Inhalt aufgrund von Verschleißausgleich nicht gelöscht).

Andy Dent
2014-12-07 11:49:37 UTC
view on stackexchange narkive permalink

Das ursprüngliche Beispiel zeigt eine Stapelvariable, da es sich um einen nativen Int-Typ handelt.

Das Überschreiben ist eine gute Idee, da es sonst auf dem Stapel verbleibt, bis es von etwas anderem überschrieben wird.

Ich vermute, wenn Sie sich in C ++ mit Heap-Objekten oder C-nativen Typen befinden, die über Zeiger und Malloc zugewiesen wurden, ist es eine gute Idee,

  1. volatile
  2. Verwenden Sie Pragmas, um den Code mit dieser Variablen zu umgeben und Optimierungen zu deaktivieren.
  3. Wenn möglich, stellen Sie das Geheimnis nur in Zwischenwerten und nicht in benannten Variablen zusammen, damit es nur existiert während der Berechnungen.
  4. ol>

    Unter der JVM oder C # denke ich, dass alle Wetten ungültig sind.

* "Wenn möglich, stellen Sie das Geheimnis nur in Zwischenwerten und nicht in benannten Variablen zusammen." * Dies ist wenig sinnvoll, da die meisten von Versionen kompilierten Binärdateien keine Namensinformationen enthalten. Wenn ich eine C ++ - kompilierte Anwendung zerlege, kann ich feststellen, welche Anweisungen sie ausführt, aber mit ziemlicher Sicherheit kann ich keine Variablennamen nennen.
Ich kann mich irren, aber ich habe darüber nachgedacht, wo Zwischenwerte gespeichert werden, im Gegensatz zu einzelnen Werten, die einer Variablen zugewiesen sind. Wenn Sie eine Konstante in Ihren Code einfügen und einer Variablen zuweisen, wird diese Konstante irgendwann mit einem Wert in einem statischen Block verknüpft. Zwischenwerte existieren entweder in Registern oder intern im Chip-Cache. Wenn Sie eine Art Schlüssel als Zwischenwert berechnet und dieses Ergebnis dann mit einem Wert aus einem Dienst verglichen haben, ist das Ganze viel vorübergehender.
ratchet freak
2014-12-05 18:00:31 UTC
view on stackexchange narkive permalink

Es ist möglich, dass der Speicherblock ausgelagert wurde, bevor Sie ihn gelöscht haben. Dies hängt davon ab, wie die Nutzungsverteilung in der Auslagerungsdatei abgespielt wird. Die Daten können dort für immer leben.

Um das Geheimnis erfolgreich vom Computer zu entfernen, müssen Sie zunächst sicherstellen, dass die Daten niemals den dauerhaften Speicher erreichen, indem Sie die Seiten anheften. Stellen Sie dann sicher, dass der Compiler die Schreibvorgänge in den zu löschenden Speicher nicht optimiert.

PaulOverflow
2014-12-17 13:20:34 UTC
view on stackexchange narkive permalink

Eigentlich lautet die Antwort ja, Sie sollten sie wahrscheinlich überschreiben, bevor Sie sie löschen. Wenn Sie ein Webanwendungsentwickler sind, sollten Sie wahrscheinlich alle Daten überschreiben, bevor Sie die Funktionen delete oder free verwenden.

Beispiel für diesen Fehler ausgenutzt:

Der Benutzer kann einige schädliche Daten in das Eingabefeld einfügen. Sie fahren mit den Daten fort und rufen dann die Funktion free des zugewiesenen Speichers auf, ohne ihn zu überschreiben, damit die Daten im Speicher verbleiben. Dann lässt der Benutzer Ihre Webanwendung fallen (z. B. durch Hochladen eines sehr großen Bildes oder ähnliches), und das UNIX-System speichert den Kernspeicherauszug in core oder core. <pid> -Datei. Wenn der Benutzer dann den <pid> brutal ausführen kann, was nicht zu lange dauert, wird die Core-Dump-Datei als Web-Shell interpretiert, da sie die schädlichen Daten des Benutzers enthält.

mincewind
2014-12-17 13:52:09 UTC
view on stackexchange narkive permalink

Ist int secret = 13123 nicht eine Konstante im lokalen Bereich?

Sie sollten sich nicht zu sehr mit dem beschäftigen, was Sie schreiben, und es lohnt sich nicht, gelesen zu werden. In der Tat würde ich in ein paar konträren Ratschlägen vorschlagen, dass Sie es absichtlich lesbar lassen. Füllen Sie es außerdem zufällig mit zeitlich korrelierten Zeichenfolgen, die nicht wie gewohnt aufgerufen werden.

Auf diese Weise können Sie genau feststellen, wie es gemacht wurde, wenn Sie dunkle Websites überprüfen, um herauszufinden, ob Sie kompromittiert wurden. Da ein DB-Dump von einem Scraper-Dump getrennt ist.



Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...