Frage:
Wäre der Heartbleed-Fehler verhindert worden, wenn OpenSSL in Go / D / Vala geschrieben worden wäre?
oliver
2014-04-09 00:27:53 UTC
view on stackexchange narkive permalink

IIUC the Heartbleed vulnerability happens due to a bug in the C source code of OpenSSL, by performing a memcpy() from a buffer that is too short. I'm wondering if the bug would have been prevented automatically in other languages that have higher-level memory management systems than C or C++.

In particular, my understanding is that Go, D and Vala each compile to native code, don't need a VM to run, and should allow writing native libraries which provide a C-compatible binary interface.

So, could these languages be used to implement the OpenSSL library with the same interface, and would they offer protection against bugs like the Heartbleed vulnerability?

Fehler passieren. In dem Moment, in dem Sie davon ausgehen, dass die Verwendung einer bestimmten Programmiersprache Sie vor Fehlern schützt, treten diese * mehr * auf und es wird umso schlimmer, wenn (nicht wenn) sie auftreten, weil Sie nie angenommen haben, dass dies möglich ist.
@Shadur Aber nicht alle Fehler sind gleich und verschiedene Sprachen neigen zu verschiedenen Arten von Fehlern. Es ist unaufrichtig, das Problem mit der Hand zu winken, indem man sagt "Sie werden immer Fehler haben", was wahr ist, aber nur leer. Es ist, als würde man behaupten, dass Menschen bei Autounfällen immer noch sterben, daher sind Sicherheitsgurte unwirksam, um Todesfälle zu verhindern. Es ist nicht so, dass ich Ihnen im Geiste nicht zustimme, aber es ist albern zu erwarten, dass bestimmte Klassen von Fehlern, die nur in einer unsicheren Sprache auftreten können, in einer sicheren Sprache auftauchen.
@Doval Es ist ebenso unaufrichtig zu behaupten oder zu implizieren (wie die Frage), dass dieses Problem nicht existiert hätte, wenn nur diese armen, unwissenden Menschen das Licht gesehen und openSSL in einer "* richtigen *" Sprache geschrieben hätten. Um die Metapher zu verwenden, sage ich nicht, dass Sicherheitsgurte nutzlos sind, ich sage, dass der Fragesteller fälschlicherweise impliziert, dass das Tragen eines Sicherheitsgurts Sie vor allen möglichen Unfällen schützt.
@Shadur Aber niemand schlug so etwas vor. Zu fragen, ob * dieser spezielle Fehler * in einer sicheren Sprache hätte verhindert werden können, ist eine absolut legitime Frage. Wenn das OP den Eindruck hätte, dass eine sichere Sprache * alle * Fehler verhindern könnte, die OpenSSL hatte / haben wird, wäre das anders. aber er erwähnte spezifisch "memcpy" und "übergeordnete" Speicherverwaltung.
Fünf antworten:
Thomas Pornin
2014-04-09 02:49:32 UTC
view on stackexchange narkive permalink

Eigentlich hätte keine dieser Sprachen den Fehler verhindert, aber sie hätten die Konsequenzen verringert.

OpenSSLs Code tut etwas, was aus Sicht der abstrakten Maschine unsinnig ist: Es liest mehr Bytes aus einem Puffer als tatsächlich in einem Puffer. Mit C "funktioniert" der Lesevorgang immer noch und gibt alle nach dem Puffer verbliebenen Bytes zurück. Bei strengeren Sprachen wäre der Speicherzugriff außerhalb der Grenzen abgefangen worden und hätte eine Ausnahme ausgelöst: Anstatt die Bytes zu lesen und zu senden, stürzte der fehlerhafte Code einfach ab und führte (im Kontext eines Webservers) zur Beendigung von Der aktuelle Thread und wahrscheinlich das Schließen der Verbindung, ohne den Rest des Servers zu verändern.

Also immer noch ein Fehler, aber keine echte Sicherheitslücke mehr.

Dies hat nur eine indirekte Beziehung zur automatischen Speicherverwaltung. Das eigentliche Sicherheitsnetz ist hier die systematische Überprüfung der Array-Grenzen bei Zugriffen. Diese systematische Überprüfung wird dann indirekt durch die strikte Typisierung unterstützt (die verhindert, dass etwas anderes als ein "Array von Bytes" als "Array von Bytes" verwendet wird). Strenge Typen werden selbst indirekt von der automatischen Speicherverwaltung (GC) unterstützt, da sie baumelnde Zeiger und damit die Bedingungen für die Verwendung nach dem freien Gebrauch verhindern, die gegen die strikte Typisierung verstoßen neues Ding; OpenSSL hatte im Laufe der Jahre bereits einige Fehler im Zusammenhang mit Pufferüberläufen (von denen einige aus dem ASN.1-Verarbeitungscode für das Parsen von Zertifikaten stammen). Dieser ist nur ein weiterer in der Liste.

Steffen Ullrich
2014-04-09 02:37:49 UTC
view on stackexchange narkive permalink

Wenn Sie den Fehler als Auslesen außerhalb der Grenzen der aktuellen Struktur betrachten, wäre dies wahrscheinlich in anderen Sprachen verhindert worden, da man keinen ungebundenen Zugriff auf den Speicher hat und diese Dinge anders implementieren müsste.

Aber ich würde diesen Fehler lieber als fehlende Validierung von Benutzereingaben klassifizieren, z Es wird davon ausgegangen, dass die im Paket gesendete Größe tatsächlich der Größe der Nutzlast entspricht. Diese Art von Fehlern wird nicht einfach durch die Verwendung einer anderen Sprache behoben.

Der Fehler wäre also vorhanden, aber es wäre keine große Sicherheitslücke
Genau dieser Fehler ist möglicherweise nicht vorhanden oder hat keine Konsequenzen, aber es gibt genügend schwerwiegende Fehler bei der Eingabevalidierung, die möglicherweise einen ähnlichen Schweregrad haben. Schauen Sie sich die glänzende Web2.0-Welt an, in der es nicht um ungebundene Lesevorgänge, sondern um XSS- und CSRF-Angriffe geht, um Millionen von Routern und deren Benutzer zu gefährden.
Die Erkennung nicht bereinigter Eingabedaten * kann * jedoch eine Sprachfunktion sein, wie dies in Netscape JavaScript und heute in Ruby der Fall war. Siehe meine Antwort unten
codebeard
2014-04-10 13:31:11 UTC
view on stackexchange narkive permalink

Unfortunately, the bug would not have been prevented, because OpenSSL uses its own memory allocator, rather than the one provided by the system.

The buffer from which the infamous heartbeat data is read is allocated by a function called freelist_extract in ssl/s3_both.c. This function, by default, manages OpenSSL's own list of used/unused memory, and does none of the modern safety checks.

Even if it had been written in another language, assuming that OpenSSL had still kept maintaining its own buffer allocator, then this bug would have happened just the same. By reusing a previous buffer structure, regardless of the programming language, the memcpy or "buffer copy" function equivalent would have done the same thing without raising any errors.

In a modern programming language, this would be something like:

request = last_used_buffer;/* I'm sure it doesn't actually read bytes like this, but you get the idea */while (byte = read(connection)) {    request[i++] = byte;}/* ... some time later, in the heartbeat processing function */output = new Buffer();output.write(header);output.write(request, start, len); /* dutifully copies from the request buffer,                                      but since end was not checked, it can copy                                      bytes from last_used_buffer */

If instead, OpenSSL had been directly using the system (libc) malloc and free rather than its own allocator, this bug might have been caught a couple of years ago. Many libc implementations provide much better bounds checks on allocated/freed memory, and tools like valgrind could have picked up this bug easily.

This consequence of OpenSSL's memory allocator in the working of the heartbleed bug was mentioned by Ted Unangst at: http://www.tedunangst.com/flak/post/heartbleed-vs-mallocconf

pyramids
2014-04-09 02:55:05 UTC
view on stackexchange narkive permalink

I think I can answer this question for the specific case of a crypto library written in Go---it is easy, and not at all hypothetical, because there already is a standalone TLS package, crypto/tls in Go that does not depend on any outside library.

Whilst with regard to typical buffer overflows, idiomatic Go is much safer than traditional C, Go offers the keen developer plenty of options to sidestep it---such as imitating C's pointer arithmetic through Go's unsafe.pointer. One wonders if one could agree not to use fragile code in a critical piece of software.

Cryptography, of course, is exactly the kind of software using such fragile code, for good reasons. After all, the constant-time comparisons implemented in the Go package crypto.subtle do indeed require, and have, similarly dire warnings about careful use as those from unsafe. The only remaining question, really, is if any bug can still survive in such an environment.

As far as I can tell, Go indeed implements constant time comparisons of hash values correctly. I haven't bothered to even look if complicated hashes involving S-boxes are calculated in a constant-time fashion---nobody bothered putting them into a package with names such as subtle and warnings about how easy it is to break things, so I'm actually doubtful.

What I did check is that elliptic curve cryptography is not implemented in a constant-time fashion in Go. Nobody even seems to have considered trying in the least---the implementation calls many arbitrary-length integer functions not even designed for cryptographic use, and indeed using non-constant-time algorithms. When this kind of timing side-channel was recently shown to also happen in OpenSSL on one architecture, it was good enough for a paper demonstrating private key compromise.

The same, continuing situation exists in Go, on all architectures. And, well, it doesn't really seem anyone cares about such details as actually working crypto; the focus is just on readability and speed (well, and working in the way that the casual user and some unit tests are fooled by it, I guess). After all, why would you even bother choosing a suitable algorithm when the language already keeps you safe from most ways of introducing buffer overflows, and when choosing a correct algorithm risks ruining Google's assertion that TLS has become computationally cheap? Sarcasm aside, making the language responsible for catching our bugs will just mean all those bugs the language cannot catch for us will still be there.

Finally, libraries like OpenSSL have the advantages that timely bugfixes are a reasonable possibility. Whilst in principle the same is true for Go packages, once something becomes part of Go's core, like the TLS package, it does become affected by the release schedule. Obviously that can interfere with timely deployment of bugfixes. I suppose Go-1.3, due this summer, will certainly not fix the ECC timing issue even if it were recognized as the critical issue it is, given the feature freeze.

Verstehe ich das also richtig: Die Vorteile von Go würden für eine gute OpenSSL-Neuimplementierung zunichte gemacht, da der Code mit unsicheren Grundelementen auf niedriger Ebene geschrieben werden müsste, um Timing-Angriffe zu verhindern? Daran hätte ich nie gedacht.
Nein; Wenn meine Antwort diesen Eindruck vermittelt, ist meine Antwort falsch. Der Punkt ist, dass eine sehr ähnliche Art von Gefahr in hochrangigen Aspekten lauert, die in der vorhandenen Go-Bibliothek mindestens genauso schlecht sind wie in OpenSSL.
Sie beantworten die Frage des OP nicht, obwohl Sie einen fairen Punkt machen. Ich würde sagen, "eine sichere Sprache würde in der Tat ein uneingeschränktes Lesen verhindern, was Sie fragen, aber da Sie Kryptosoftware neu implementieren müssen, benötigen Sie immer noch eine Experten-Sicherheitsüberprüfung, um Krypto-Fehler auf hoher Ebene zu verhindern." Das Schreiben von OpenSSL-Code erfordert die gleiche Überwachung + Verhinderung von Fehlern, die nur in einer unsicheren Sprache möglich sind.
Wenn Sie also SSL neu implementieren möchten (was einige Leute tun, siehe PolarSSL), benötigen Sie einen Krypto-Experten und möchten möglicherweise eine bessere Sprache verwenden (alternativ, um statische Analysen in Ihren Workflow einzubeziehen, wie dies für PolarSSL der Fall ist). ;; Ich würde sagen, letzteres ist in Bezug auf die Sicherheit eine minderwertige Alternative, aber besser als nichts.
piers7
2014-04-10 19:23:41 UTC
view on stackexchange narkive permalink

Data Tainting wurde in Netscape JavaScript (Navigator 3 und auf dem Server in Enterprise Server) als Reaktion auf relativ frühe Erkenntnisse über die Art der Sicherheit im Internet implementiert. Alle vom Benutzer eingegebenen Eingaben wurden als fehlerhaft eingestuft, es sei denn, das Flag wurde gelöscht, und das fehlerhafte Flag wird über Operationen an Daten verbreitet (das Ergebnis der Kombination von Daten und fehlerhaften Daten wird daher als fehlerhaft angesehen). Infolgedessen konnten verschmutzte Daten immer überprüft werden.

Dies war vor über 10 Jahren . Es hat mich umgehauen, dass dies nicht in die gängigen verwalteten Sprachen wie Java oder C # (oder in die JavaScript-Implementierung eines anderen) eingedrungen ist.

Wenn Sie die Analyse von Datenverschmutzungen zur Kompilierungszeit mit einem Safe kombiniert haben Speichermodell (verwalteter Code oder zumindest überprüfbar), Sie würden zwar immer noch logische Fehler haben, aber Sie hätten auf einen Schlag ganze Kategorien von Angriffen eliminiert, einschließlich beider Faktoren, die zu diesem beitragen.

Data Tainting ist in Perl viel länger implementiert und kann noch heute verwendet werden. Es wird jedoch nur erzwungen, dass Sie die Daten irgendwie überprüfen, nicht die Qualität der Überprüfung. Ich habe genug Code gesehen, der nur mit dem Platzhalter verglichen wird, um die Daten unberührt zu lassen. Und es hilft definitiv nicht, die genaue Logik herauszufinden, die Sie benötigen, um eine Zeichenfolge in eine JavaScript-Anweisung einzubetten, die in ein HTML-Attribut usw. eingefügt wird, und um zusätzlich browserspezifische Unterschiede bei der Interpretation dieser Daten zu umgehen. Ich stimme jedoch zu, dass das Verschmutzen eine nützliche Funktion ist, um einen Teil der Probleme zu lösen.


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...