Mittwoch, 19. Mai 2010

Sichere Zufallszahlen mit ActiveSupport::SecureRandom

Auch wenn es manchmal anders scheint: Kaum etwas ist für eine deterministischen Maschine (also einen Computer) so schwierig, wie ein echt "zufälliges" Ergebnis zu erzeugen. Die gleiche Berechnungsvorschrift mit den gleichen Parametern ergibt nun mal per se immer das gleiche Ergebnis.

Weil man häufig mal beim Programmieren aber ein zufälliges Ergebnis braucht, behilft man sich typischerweise mit "Pseudo"-Zufallsgeneratoren. Die basieren auf komplizierten mathematischen Formeln, die ausgehend von einem Startwert deterministisch eine zufällig erscheinende Zahlenfolge erzeugen. Dieser Startwert wird dann beim Programmstart intialisiert, z.B. auf die aktuelle Systemzeit. Dieser "Zufall" ist wohl gut genug, um in iTunes für die zufällige Anordnung einer Playlist zu sorgen, aber es handelt trotzdem um eine deterministische Berechnungsreihe, und zwar eine, deren Startwert relativ leicht erratbar ist (die Systemzeit), das heißt mit ein bisschen Mühe ist Ihr Ergebnis vorhersagbar.

Deswegen sind solche Pseudo-Zufallsgeneratoren für alle sicherheitskritischen Anwendungsfälle absolut ungeeignet. Was also tun? Moderne Betriebssysteme bieten häufig Funktionen an, die "gute" Zufallswerte liefern. Dazu nutzen sie externe Ereignisse als Quelle von "Zufall" -- z.B. Tastendrücke, Netzwerkpakete, Interrupts, die geschickt den generierten Psuedozufallszahlen beigemengt werden. Weil es schwierig ist, alle diese externen Signale genau genug zu beobachten, vorherzusagen, oder nachzuspielen, sinkt damit die Chance rapide, dass ein Angreifer die Zufallszahlen vorhersagen kann.

Leider sind diese modernen Mechanismen aber eben vom konkreten Betriebssystem abhängig, und teilweise schwer zu verwenden. Deshalb ist es praktisch, dass uns Rails diesen Aufwand erspart, indem es uns eine hübsche Bibliothek zur Verfügung stellt: ActiveSupport::SecureRandom. Unter dem Strich lässt sich damit ein Zufallswert, z.B. ein Cookie für eine E-Mail-Bestätigung damit trivial erzeugen:




require 'securerandom'
p SecureRandom.hex(12)
#=> "52750b30ffbc7de3b362"

>> SecureRandom.base64(12)
=> "n7pKog8eliVZm8Pq"


Das ist einfacher und tausend mal besser, als eine SHA1-Summe eines Pseudo-Zufallswerts zu bilden. Also, vor dem Benutzen von Kernel.rand nachdenken, ob die "Zufalls"zahl in irgendeinerweise sicherheitsrelevant ist, und im Zweifelsfall lieber SecureRandom benutzen!

Keine Kommentare:

Kommentar veröffentlichen