Mcrypt-Passwort als blob-Satz in Datenbank

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Mcrypt-Passwort als blob-Satz in Datenbank

    Moin ^^

    Szenario: ein Passwort wird mittels mcrypt (blowfish/cfb) verschlüsselt und in deiner DB-Tabelle als blob-Datensatz gespeichert, also binär(?)

    Anwendung: dieses Passwort wird mit jedem Seitenaufruf gelöscht und neu in die DB geschrieben, allerdings wird es immer mit dem gleichen Key erzeugt (das soll mir quasi eine zweite Session erzeugen, da das Passwort nach relativ kurzer Zeit ungültig werden soll, egal, einfach hinnehmen ^^)

    Problem: Wenn ich diese Seite öfter neu lade, bekomme ich irgendwann einen SQL-Fehler mit Fehlercode 0. Die Anzahl der Seitenaufrufe spielt dabei keine Rolle, mal kommt es direkt beim erstn mal neuladen, mal nach 20 Versuchen. Das Passwort wird wie gesagt bei jedem Aufruf gleich erzeugt, also mit gleichem zu verschlüsselndem Passwort und dem jeweils gleichen Key, es sollte also immer das gleiche verschlüsselte Passwort an die DB geschickt werden (wird es auch, sofern ich das mit echo prüfen kann...)


    War mir jetzt nicht sicher, ob das eine php-Problematik oder doch eher an mySQL hängt. Kann mir jemand irgendwie weiterhelfen?

    Danke schonmal im Voraus.
  • Mmh, hab keine Ahnung was ich groß an Code posten soll... ^^ ok...

    Hiermit erzeug ich relativ harmlos mein verschlüsseltes Passwort:

    Quellcode

    1. $mcrypt = mcrypt_module_open('blowfish', '', 'cfb', '');
    2. $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($mcrypt), MCRYPT_RAND);
    3. mcrypt_generic_init($mcrypt, $key, $iv);
    4. $crypted = mcrypt_generic($mcrypt, $message);
    5. mcrypt_generic_deinit($mcrypt);
    6. return $iv.$crypted; // $newpass


    Und... naja, das wäre die SQL-Anweisung, eigentlich relativ harmlos:

    Quellcode

    1. INSERT INTO ".EXE_P."_authenticate (userID, type, typeID, stamp, pass) VALUES ('".CDF::getUser()->userID."', 'db', '".$this->dbID."', '".time()."', '".$newpass."')


    Naja, die Anweisung wird quasi mit jedem Seitenaufruf ausgeführt, wobei der Eintrag vorher mit jedem Aufruf gelöscht wird (hat seine Gründe ^^)
  • [Blockierte Grafik: http://www.arexx.com/forum/images/smilies/glaskugel_smiley.gif] is klar ne ;)

    Mag schon sein, das dass alles so seine Gründe hat. Aber wenn ich nicht nachvollziehen kann, was bei der ersten Aktion passiert und dann bei der Zweiten kann ich den Fehler auch nicht nachvollziehen. Ich denke mal, die erste Aktion wirft einen Fehler oder arbeitet nicht immer korrekt.

    Ein gesamtes Bild währe da weitaus interessanter. Mit einem "is halt so" "is es halt ned einfach, nen Fehler zu finden"...
    My lovely mister singing club...
  • Alles klar, wall of text incomming ;)

    ich bastel (eher zum Spaß und privaten Gebrauch) ne kleine Applikation, mit der ich Datenbanken (lokal oder auf externen Servern) miteinander synchronisiere. Zu diesem Zweck muss ich mich ja mit den Datenbanken verbinden. Da ich das DB-Passwort natürlich nicht im Klartext in der DB der Applikation speichern möchte, wird es durch ein individuelles Benutzerpasswort verschlüsselt (via Mcrypt).
    Hat der Benutzer sich in die DB "eingeloggt" erzeuge ich eine Art Session (siehe SQL-Statement letzter Post), das gleiche funktioniert auch für FTP-Zugriffe, deswegen die type-Spalte. Wie auch immer, die Sache läuft objektorientiert, der Benutzer will zu einer DB verbinden, es wird ein entsprechendes Objekt angelegt... in einer Methode zum Verbinden wird halt geprüft, ob bereits eine "Session" zu der userID vorhanden ist, wenn ja, wird diese gelöscht und neu angelegt. Ja, das is eigentlich absolut sinnfrei, da hat mich ein anderer Gedanke getrieben, den ich wieder verworfen habe, aber das ist nunmal das Szenario in dem der Fehler auftritt.

    Fakt ist jedenfalls, das diese "Aktualisierung der Session" mal funktioniert und mal nicht, bei gleichbleibenden Eingaben (ok, wie man im SQL_Statement sieht bau ich ne timestamp ein, aber das sollte ja soweit passen) und ich hab keine Ahnung wieso. Klar, ich werd diese sinnfreie Löschaktion wieder ausbauen, aber mich würd halt trotzdem interessieren, wie es zu diesem Fehler kommen kann :)
  • Hey,

    ich hatte vor zwei Tagen ein ähnliches Problem in der Arbeit. Mal ging es, mal nicht. Bei mir lag es an einer falschen Abfrage an der DB. Die hat Resultate zurück geliefert, später aber mit anderen Daten im PHP-Script für Probleme gesorgt. Somit konnte die nächste Abfrage nicht sauber geführt werden.

    Was ich jetzt probieren würde, währe Stück für Stück in einer Testdatei das Szenario nachbauen, um den Fehler zu finden.
    Also wirklich reinstes SQL (keinerlei Dynamische Daten im Statement), das dir den Eintrag löscht und dann neu anlegt. Dann fängst du langsam an (mit zwischenzeitlichen Tests), dein Script so wieder aufzubauen bis du den Fehler gefunden hast. Das hatte mir bei meinem Problem sehr geholfen (gerade weil auch mal ging und mal nicht, die Abfrage aber exakt gleich war).

    Ich hoffe das hilft. Ansonsten müsste ich auch den kompletten Code sehen/bekommen und den Fehler erst reproduzieren um das Problem wirklich zu verstehen, du verstehst? ;)

    Gruß,
    Erasel
    My lovely mister singing club...
  • @Erasel
    verstehe was du meinst, danke für die Erinnerung, man hält sich ja manchmal für so gut, solche Fehler direkt ausschließen zu können ^^ aber trotz Nachbildung komm ich auf den gleichen Fehler.

    @d0nut
    an sowas hatte ich eher gedacht, bin aber ziemlicher Anfänger auf dem Gebiet... also geht über intval, addslashes und ggf. htmlentities nich hinaus. Besagte Fälle fange ich vorher entsprechend ab. Ich hab ehrlich gesagt keine Ahnung, ob/wie ich das Passwort vernünftig ablegen sollte, bzw. wie ich mit dem kodierten String umgehen soll (die Schreibweise is verdammt gewöhnungsbedürftig). Bytecode war nur eine Idee, weil ich es nicht als String behandeln kann

    Hier auch nochmal die einzige Fehlermeldung, die ich rausziehen kann:

    Invalid SQL: INSERT INTO sync_authenticate (userID, type, typeID, stamp, pass) VALUES ('1', 'db', '18', '1274345851', '���q JK'}�c�')

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Masterog ()

  • Zweiter Anlauf:

    Ich hab jetzt für jeden Schritt der Verbindung eine Testausgabe eingebaut und siehe da, irgendwann funktioniert die Entschlüsselung nicht mehr. Der Ablauf ist wie folgt:
    1. Lies das verschlüsselte Passwort aus der Session-Tabelle
    2. Entschlüssel das Passwort mit einem Key(*)
    3. Verbinde dich mit der Datenbank mittels entschlüsselten Passworts
    4. Verschlüssel das Passwort wieder mit dem Key(*)
    5. Speicher das neue Passwort in der Session-Tabelle
    Der Key(*) setzt sich aus Objektvariablen zusammen, die wiederum aus einer Datenbank kommen, in diesem Fall ohne Sonderzeichen oder irgendwelche Besonderheiten
    Irgendwann kommt bei Schritt 2 nicht mehr das Originalpasswort raus, sondern wieder etwas unleserliches, was in Schritt 4 zu irgendwas verschlüsselt wird, was der Anweisung in Schritt 5 scheinbar nich gefällt.
    Auffallend ist, dass in Schritt 4 immer ein anderes verschlüsseltes Passwort erzeugt wird, aber das (wenn ich mich recht erinner) dem blowfish entsprechen, oder?

    Zur Ver- und Entschlüsselung verwende ich die McryptUtil.class.php aus dem Wiki

    Da die Objektvariablen, die ich als Key verwende, unverändert sind, muss der Fehler ja eigentlich in meiner Handhabung/Speicherung des verschlüsselten Passworts liegen, oder?
    Ich hab nur blob als Typ verwendet, weil ich bei text, also string, ein sql-insert error bekomme...

    Hat da jemand Hilfe anzubieten, oder Erfahrung, oder Ideen? Bin für alles offen ^^
  • das "Problem" mit dem binary löst du übrigens mit base64 encoding ;)

    Quellcode

    1. $lesbar = base64_encode($blowfish_unlesbar);


    Der Blowfish String ist auch bei gleichem Key und gleichem Passwort immer identisch:

    Quellcode

    1. <?php
    2. $data = 'meinpasswort';
    3. $key = 'easycoding';
    4. for($i=0; $i<10; $i++) {
    5. $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
    6. echo base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_ECB, $iv)).'<br/>';
    7. }


    Fehler bei dir?

    Allgemein: Der Schlüssel ist systemweit.. immer wenn es systemweit geändert wird, wird der Login für den Benutzer nicht mehr möglich sein.
    Für dich ist es gleichzeitig auch nicht mehr möglich das alte Passwort wiederherzustellen. Wo liegt der Sinn ein einem solchen Systems?
    Warum speicherst du das Passwort überhaupt mit dem selben Key nochmal zurück? Es sollte der selbe String sein.

    Immer wenn sich der Schlüssel ändert, dann kommt beim decodieren Datenschrott raus. Blowfish gibt dir kein "false" für nicht möglich.
  • Grüße ^^

    danke für den Tipp mit dem base64, hätte man echt selbst drauf kommen können, wenn man sich etwas mehr damit befasst hätte ;(

    Ich hatte gehofft, es käme immer das gleiche Passwort raus, als ich das Codebeispiel aus dem Wiki gelesen hatte, ist mir halt dieser Zufallswert MCRYPT_RAND aufgefallen, und da mein Passwort immer anders aussah, dachte ich da einen Zusammenhang gefunden zu haben.

    Wenn ich dein Codebeispiel verwende kommt tatsächlich immer das gleiche raus, wie gesagt habe ich die McryptUtil von SargTeX aus eurem Wiki testweise verwendet, hier nochmal die entsrepchenden Methoden:

    Quellcode

    1. public static function open($algorithm = 'blowfish', $mode = 'cfb') {
    2. self::$mcrypt = mcrypt_module_open($algorithm, '', $mode, '');
    3. }
    4. public static function encrypt($crypt, $mcryptKey) {
    5. $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size(self::$mcrypt), MCRYPT_RAND);
    6. mcrypt_generic_init(self::$mcrypt, $mcryptKey, $iv);
    7. $crypted = mcrypt_generic(self::$mcrypt, $crypt);
    8. mcrypt_generic_deinit(self::$mcrypt);
    9. return $iv.$crypted;
    10. }
    11. public static function decrypt($crypt, $mcryptKey) {
    12. $ivsize = mcrypt_enc_get_iv_size(self::$mcrypt);
    13. $iv = substr($crypt, 0, $ivsize);
    14. $crypt = substr($crypt, $ivsize);
    15. mcrypt_generic_init(self::$mcrypt, $mcryptKey, $iv);
    16. $crypt = mdecrypt_generic(self::$mcrypt, $crypt);
    17. return $crypt;
    18. }
    Alles anzeigen


    Nehme ich jetzt folgendes Beispiel:

    Quellcode

    1. McryptUtil::open();
    2. for($i=0; $i<10; $i++) {
    3. $crypted = McryptUtil::encrypt("easycoding", "meinpasswort");
    4. echo base64_encode($crypted)." -> ".McryptUtil::decrypt($crypted, "meinpasswort")."<br>";
    5. }


    erhalte ich folgende Ausgabe:

    Quellcode

    1. U/UP7mqD5JjXUKD7+uyiIILd -> easycoding
    2. BO0xyWjcS6wI+YYidfyXRuUX -> easycoding
    3. q/PYgfxj171gi+CS+Zwc1Mj6 -> easycoding
    4. CMfG1+bXS40xAy+qEWa/LpaF -> easycoding
    5. 2yq6jOb6Y9oD41YfU4QllDIB -> easycoding
    6. 5NlzX72M4WYyb5QZwgMhH6Wt -> easycoding
    7. 45ezEClLhu+aKUr72HQV12CX -> easycoding
    8. mSQ5Xuv3EjdFpEIPTuRvArZC -> easycoding
    9. xD7ECsNTQvtOs3NnWTuq6egM -> easycoding
    10. JaUX1HIc2ABLyQhlqVKYFqgP -> easycoding


    Also jedesmal ein anderes Passwort. SargTeX verwendet auch andere Methoden und nen anderen Algorithmus als du (oder?), da ich von dem Gebiet relativ wenig Ahnung hab, war copy&paste angesagt.

    Wie auch immer, ich habe die Klasse mal angepasst und mich dabei an dein Beispiel gehalten, siehe da, alles funktioniert wunderbar, die Passwörter sind jetzt tatsächlich identisch ^^
    Der zu Beginn genannte SQL-Fehler kommt vermutlich von den Bytedaten die ich speichern wollte... zumindest bekomm ich nach base64 keine Fehler mehr, auch bei den alten "variierenden" Passwörtern. Da bietet MySQL extra ein Byteformat an und ich bin auf Grund mangelnder PHP-Kentnisse zu doof, das zu nutzen... wird nachgeholt.

    Zu deiner Frage, was die wiederholte Speicherung soll: da hast du natürlich absolut recht und ich hatte weiter oben ja schon geschrieben, dass ich besagte Verfahrensweise entferne. Das war einfach ein wiederverwendetes Relikt aus grauer Vorzeit und in diesem Kontext ziemlich unnütz ^^ Trotzdem hat es mich interessiert, wie es zu dem Fehler kommt, irgendwie muss man ja lernen, oder? ;)

    Also, vielen Dank nochmal für die Hilfe


    Eine letzte Frage doch noch: Das Beispiel hat ja auch mit SargTeX Version, also den variierenden Passwörtern, funktioniert. Gibt es ne Art Schlagwort, unter dem ich die verschiedenen Algorithmen, die in Mcrypt verwendbar sind, vergleiche kann? Oder heißt es auch hier sich in jeden Algorithmus einlesen und seinen Liebling zu finden?
  • Du hast recht - in meinem Beispiel habe ich den AES Algorithmus verwendet. Hier nochmal die Blowfish Variante für alle die es vllt interessiert.
    Ergibt auch einen identischen Output:

    Quellcode

    1. $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB), MCRYPT_RAND);
    2. echo base64_encode(mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_ECB, $iv)).'<br/>';


    Zu den verschiedenen Algorithmen. In der Tat kann hier jeder selbst unterscheiden.
    AES bzw Rijndael ist eben standardisiert worden und hat den größten Support an Programmiersprachen.

    Blowfish ist relativ unpopulär, wird wegen seiner Top Performance aber manchmal vorgezogen. Ich habe auf der Arbeit mal alle gegeneinander gebenchmarkt und in der PHP Implementierung war AES schneller als Blowfish und sein Nachfolger Twofish. Ich kann daher nur AES empfehlen. Beste Unterstützung, beste Performance.
    Wenn ich den Benchmark mal wieder finde, werde ich ihn im Wiki veröffentlichen.

    Lg