WernerK: PHP Fatal error: Uncaught Exception: Could not gather sufficient random data in Stack trace: #0 C:\inetpub\wwwroot\test\test.php(3): session_start()

Hallo,

kann jemand mit dieser Fehlermeldung etwas anfangen?

PHP Fatal error: Uncaught Exception: Could not gather sufficient random data in Stack trace: #0 C:\inetpub\wwwroot\test\test.php(3): session_start()

Laut meiner Recherche müsste das ein Session Problem sein dass keine Session angelegt werden kann? PHP 7.1.14 wurde neu auf einem Server 2012 in IIS installiert unter C:\PHP. Darunter habe ich dann C:\PHP\tmp\sessions angelegt. Hier im Security Tab die Rechte für IUSR vergeben. Dann in der PHP.ini den Session.save_path angepasst und danach den IIS neu gestartet.

Trotzdem ist immer noch diese Meldung da. Was kann es sonst noch sein?

Gruss Werner

  1. Was kann es sonst noch sein?

    Ein bekannter Bug in PHP 7.1.2:

    https://github.com/php/php-src/pull/2385

    1. Hallo Regina,

      Werner beschrieb eine Windows-Installation. Der von Dir verlinkte Pull-Request scheint sich auf Unix zu beziehen. Oder war ich zu oberflächlich? Bin jetzt nicht in den Sourcecode eingestiegen 😀

      Rolf

      --
      sumpsi - posui - clusi
      1. Werner beschrieb eine Windows-Installation.

        Ja. Aber das Problem scheint darin zu liegen, dass einer der Autoren "starken" Zufall wollte. (Literatur für Linux: [man 4 random](http://man7.org/linux/man-pages/man4/random.4.html)). Das braucht aber "Entropy" (Rauschen von Gerätetreibern und anderen Quellen) und schlägt fehl wenn diese Entropy "verbraucht" ist - was auf Servern ziemlich fix geht.

        Vorher hat man im Falle des Fehlens von Entropy wohl auf die kryptographisch nicht wirklich nützlichen Werte aus /dev/urandom zurückgegriffen. Das nutzt stumpf eine mathematische Funktion für (Pseudo-)Zufallswerte.

        PHP-intern wird eine cpp-Funktion SYS_getrandom genutzt. Und genau die dürfte letztendlich das Problem darstellen, da eben in dieser wird (über alle Betriebssysteme hinweg) der, ich nenn es mal "Syscall" aufgerufen wird und also nur noch der starke Zufall genutzt wird. Der Syscall ruft (unter Linux von /deb/random) eine gewisse Anzahl von Bytes ab, hasht diese gemäß der ini-Einstellung session.hash_func . das Ergebnis ist die Session-ID. Und eben dieses Abholen versagt (oder stockt zu lange), wenn es an Rauschen der Geräte fehlt.

        Lösung: Kamera anschließen und auf einen Ameisenhaufen oder eine belebte Kreuzung oder ein Regal voller Lava-Lampen richten. Oder eben eine gefixte Version von installieren.

        1. Vorher hat man im Falle des Fehlens von Entropy wohl auf die kryptographisch nicht wirklich nützlichen Werte aus /dev/urandom zurückgegriffen. Das nutzt stumpf eine mathematische Funktion für (Pseudo-)Zufallswerte.

          https://www.2uo.de/myths-about-urandom/

          1. Bitte verzeih mir den Fehler, dass ich mich nicht auf Aussagen in einem Blog verlasse sondern auf den Inhalt des Manuals des Herstellers:

            When read, the /dev/random device will return random bytes only within the estimated number of bits of noise in the entropy pool. /dev/random should be suitable for uses that need very high quality randomness such as one-time pad or key generation. When the entropy pool is empty, reads from /dev/random will block until additional environmental noise is gathered. If open(2) is called for /dev/random with the flag O_NONBLOCK, a subsequent read(2) will not block if the requested number of bytes is not available. Instead, the available bytes are returned. If no byte is available, read(2) will return -1 and errno will be set to EAGAIN.

            A read from the /dev/urandom device will not block waiting for more entropy. If there is not sufficient entropy, a pseudorandom number generator is used to create the requested bytes. As a result, in this case the returned values are theoretically vulnerable to a cryptographic attack on the algorithms used by the driver. Knowledge of how to do this is not available in the current unclassified literature, but it is theoretically possible that such an attack may exist. If this is a concern in your application, use /dev/random instead. O_NONBLOCK has no effect when opening /dev/urandom. When calling read(2) for the device /dev/urandom, signals will not be handled until after the requested random bytes have been generated.

            Und wie die Dinge liegen liegt das Manual des Herstellers und meine Aussage genau auf einer Linie. Aber wenn das wirklich Mythen sein sollten, dann hätte ich einen schwarzen Tag.

            1. Ich sollte noch eines ergänzen:

              Auch wenn /dev/urandom eine mathematische Funktion nutzt und also spätestens nach Verbrauch der Entropy kryptographisch zweifelhafte Zufallswerte liefert, so ist die Erzeugung der Session-IDs dennoch hinreichend sicher. Grund: Die aus /dev/urandom abgeholten Werte werden gehasht. Da aus dem Hash (jedenfalls wenn man nicht gerade MD5 oder SHA1 benutzt) die ursprünglichen Zufallswerte nicht wieder ausgelesen werden können fehlt es an einem Ansatzpunkt um aus einer gültigen Session-ID eine andere zu berechnen.

              Ein Angriff würde zu dem auf Grund des dennoch notwendigen Durchprobierens der immer noch enormen Vielzahl der "wahrscheinlicheren Variationen" zudem den Charakter einer DOS-Attacke haben - also den Server lahmlegen, sich also selbst stoppen.

            2. Bitte verzeih mir den Fehler, dass ich mich nicht auf Aussagen in einem Blog verlasse sondern auf den Inhalt des Manuals des Herstellers:

              https://www.2uo.de/myths-about-urandom/#man-page

              1. https://www.2uo.de/myths-about-urandom/#man-page

                Du hast bestimmt schon mal probiert wie weit die Entropy reicht.

                ~$ dd if=/dev/random count=1 bs=256
                L�<��_���e��ђr}6�`t|70+1 Datensätze ein
                0+1 Datensätze aus
                27 Bytes kopiert, 0,000163699 s, 165 kB/s
                
                ~$ dd if=/dev/random count=1 bs=256
                lCA2H0+1 Datensätze ein
                0+1 Datensätze aus
                6 Bytes kopiert, 12,9739 s, 0,0 kB/s
                
                ~$ dd if=/dev/random count=1 bs=256
                X0+1 Datensätze einU��S
                0+1 Datensätze aus
                33 Bytes kopiert, 0,000145708 s, 226 kB/s
                

                Mal 27, mal 6, mal 33 Bytes. Das war auf einem Desktop, zwischen den Aufrufen lagen einige Sekunden. Ich habe durch die Tastatur und die Maus Entropy geliefert. Auf einem Webserver kann das Lesen aus /dev/random weitaus öfter stattfinden ohne das Entropy geliefert wird.

                Zweiter Test: Auf einem Server (ohne Tastatur oder Maus) hat /dev/random nach 4,5 Megabytes aufgehört, Werte zu liefern und danach blockiert.

                Wenn jetzt also - auf einem Server - ohne den Nachschub an Entropy für kryptografische Anwendungszwecke Zufallszahlen gebraucht werden und - wie von Dir postuliert - das nicht blockierende /dev/urandom benutzt wird, dann tritt der Fall ein, dass der "Zufall" das Ergebnis einer mathematischen Funktion ist. Auch wenn die postulierten Angriffsmöglichkeiten sehr theoretischer Natur sind (und ich einen Angriff auf die Erzeugung der Session-ID aus sehr praktischen Erwägungen ausschließe) würde ich keineswegs dazu neigen, derart pauschal und ohne Zweckbegrenzung einen Zugriff auf /dev/random zu empfehlen wie es in dem von Dir verlinkten Blog geschieht.

                Im Falle der Sessions (und einer gewaltigen Anzahl vergleichbarer Umstände) gilt anderes, da genügt nach meiner Ansicht /dev/urandom komplett.

                Aber wenn ich mir vorstelle, ich müsste in einem Kommunikationssystem dauernd neue Keys erzeugen um Nachrichten zu verschlüsseln, dann könnte ich mir je nach gewünschtem Sicherheitslevel auch vorstellen zum Zweck der Entropyerzeugung zu einem Regal voller Lavalampen und hoch auflösenden Kameras zu raten.

                Der Blog erweckt den Eindruck, dass da jemand recht unvorsichtige absolute Aussagen tätigt und zudem alle anderen für dumm hält. Außerdem weiß ich nicht so ganz genau, was es soll, dass ich auf einer de-Domain offenbar von einem Deutschen in englischer Sprache "bedient" werde. Da wo ich herkomme macht man sich in solchen Fällen oft Sorgen, ob da nicht etwa der Gert postuliert.

                1. Wenn jetzt also - auf einem Server - ohne den Nachschub an Entropy für kryptografische Anwendungszwecke Zufallszahlen gebraucht werden und - wie von Dir postuliert - das nicht blockierende /dev/urandom benutzt wird, dann tritt der Fall ein, dass der "Zufall" das Ergebnis einer mathematischen Funktion ist.

                  Ja, die selbe Funktion, die auch die Daten aus /dev/random liefert. Der Artikel erklärt auch, warum das kein Problem sein darf.

                  Der Blog erweckt den Eindruck, dass da jemand recht unvorsichtige absolute Aussagen tätigt und zudem alle anderen für dumm hält.

                  Vielleicht solltest du den Artikel nochmal in Ruhe lesen, und dem Autoren nicht Dinge in den Mund legen, die er nicht aussagt. Der Artikel ist meiner Meinung nach ziemlich ausgeweogen und nennt auch explizit in welchen Fällen die Verwendung von /dev/urandom problematisch wäre (nämlich bei der vorhersagbaren Wiederverwendung von Seeds).

                  Außerdem weiß ich nicht so ganz genau, was es soll, dass ich auf einer de-Domain offenbar von einem Deutschen in englischer Sprache "bedient" werde. Da wo ich herkomme macht man sich in solchen Fällen oft Sorgen, ob da nicht etwa der Gert postuliert.

                  Da, wo ich herkomme, ist Englisch ganz einfach die Lingua Franca in der Informatik.

  2. Hallo WernerK,

    Was kann es sonst noch sein?

    Ein Zufallsproblem. Steht doch da 😉

    Das Session-Management muss kryptographisch starke Zufallszahlen erzeugen, um nicht erratbare Session-IDs zu bekommen. Dabei ist auf deinem System offenbar etwas schiefgegangen.

    Der relevante Sourcecode von PHP 7.1.14 verwendet Dinge, die ich noch nie selbst gemacht habe, von daher weiß ich nicht, wo man konkret suchen müsste. Die PHP-internen Funktionen sind auch nicht so geschrieben, dass der Windows-Fehlecode sichtbar würde. Möglicherweise findet sich was im Event Log des Servers.

    Es KANN an den Einstellungen des Application Pool liegen. Oder der von R.S. erwähnte Bug ist durchdringender als man meint; hast Du schon mal PHP 7.2 ausprobiert? Da ist der Random-Code komplett neu geschrieben worden, soweit ich das erkennen kann.

    Rolf

    --
    sumpsi - posui - clusi
    1. Hallo Rolf,

      danke dir.

      wie im Eingangspost beschrieben habe ich 7.1.14 installiert unter Server 2012 R2. Php info bringt nichts zurück für session.entropy_file und session.entropy_length Zumindest kann ich nichst sehen . Es werden nur die normale Session Dinge aufgelistet

      Gibt es hier unter Windows etwas zu beachten?

      Gruss Werner

      1. Hallo WernerK,

        sorry, habe mein Posting mittlerweile geändert (verdammte Mod-Rechte, da kann man ändern auch wenn schon jemand geantwortet hat).

        PHP 7.1 hat diese Einstellungen beseitigt, und ich hatte zuerst übersehen, dass Du die Version ja genannt hast. Guck meine Antwort nochmal an…

        Rolf

        --
        sumpsi - posui - clusi
        1. Hallo Rolf,

          ich hatte zuerst die neueste PHP 7.2 installiert. Ich brauche aber die Microsoft PDO Treiber für SQLSRV Verbindung. Und für diese neue PHP Version scheint es noch keine zu geben.

          Also bin ich wieder zurück auf die 7.1.14 gegangen weil es hierfür die PDO treiber gibt. 😟

          Jetzt bin ich wirklich etwas ratlos. Auf einem anderen eigenen PC von mir mit Windows 10 und IIS und PHP 7.0.20 habe ich dieses Problem nicht.

          Wäre es vielleicht ein Versuch, die 7.0.20 auf Server 2012 zu installieren, oder liegt es vielleicht eher an den 2012 Server bzw. IIS Einstellungen.

          viele Grüße

          Werner

          1. Jetzt habe ich nochmals eine Version älter genommen und PHP 7.0.27 installiert. Und siehe da: Sessions laufen einwandfrei. Die oben erwähnte Fehlermeldung kommt nicht mehr. Da soll doch einer verrückt werden. Hat mich jetzt zig Stunden gekostet. Es muss ein Bug in der 7.1.14 sein.

            Gruss

            Werner

          2. Ich brauche aber die Microsoft PDO Treiber für SQLSRV Verbindung. Und für diese neue PHP Version scheint es noch keine zu geben.

            Schon probiert?

            Compile the drivers

            The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP > 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.0* using Visual C++ 2017 v15.0. For details, please read the documentation and/or take a look at the sample build scripts.

            (Quelle: https://github.com/Microsoft/msphpsql/)

            1. Ja ich hatte die letzten Treiber von der offiziellen MS Seite genommen und dann in das ext Verzeichnis von PHP gelegt. Die wurden dann aber bei phpinfo() nicht erkannt.

              By the way: Benötigt PDO in Windows denn unbedingt einen ODBC Treiber?

              Ich versuche eine Verbindung wie folgt herzustellen:

              $conn = new PDO( "sqlsrv:server=$serverName ; Database=AdventureWorks", "", "");
              $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

              Da bekomme ich dann eine Fehlermeldung wie:

              Fatal error: No ODBC error was found in

              Gruss Werner

              1. Ja ich hatte die letzten Treiber von der offiziellen MS Seite genommen und dann in das ext Verzeichnis von PHP gelegt. Die wurden dann aber bei phpinfo() nicht erkannt.

                Wie wird php denn ausgeführt? Möglicherweise (bei Ausführen als Modul des Webservers) muss der Webserver neu gestartet werden. Läuft PHP als cgi dann nicht.

                By the way: Benötigt PDO in Windows denn unbedingt einen ODBC Treiber?

                Der Hersteller der Erweiterung schreibt:

                These drivers rely on the Microsoft ODBC Driver for SQL Server to handle the low-level communication with SQL Server.

                und er liefert diese gleich (als Preview) mit.

                Sicherheitsrelevantes Zeug machst Du ja nicht unter Windows - ODER?

                1. PHP läuft als CGI im IIS. Und ja, ich hatte den IIS hinterher neu gestartet.

                  Nein ich mache keine Sicherheitsrelevanten Dinge. Ich will nur eine PDO Verbindung zu einer SQL Server DB herstellen. Ich habe jetzt noch den ODBC Treiber installiert aber die Fehlermeldung ist trotzdem noch da.

                  Man findet dazu auch nichts im Netz.

                  Gruss Werner

                  1. Ich habe jetzt noch den ODBC Treiber installiert aber die Fehlermeldung ist trotzdem noch da.

                    Hm. Ich war ja nicht dabei. Hast Du auch Punkt 2 unter "Enable the drivers" beachtet?

                    ##Install (Windows)

                    ###Prerequisites

                    • A Web server such as Internet Information Services (IIS) is required. Your Web server must be configured to run PHP
                    • Microsoft ODBC Driver 11, Microsoft ODBC Driver 13 or Microsoft ODBC Driver 17

                    ###Enable the drivers

                    1. Make sure that the driver is in your PHP extension directory (you can simply copy it there if you did not use nmake install).
                    2. Enable it within your PHP installation's php.ini: extension=php_sqlsrv.dll and/or extension=php_pdo_sqlsrv.dll. If necessary, specify the extension directory using extension_dir, for example: extension_dir = "C:\PHP\ext". Note that the precompiled binaries have different names -- substitute accordingly in php.ini.
                    3. Restart the Web server

                    Da wäre noch was:

                    Man findet dazu auch nichts im Netz.

                    Mit der GENAUEN Fehlermeldung wird man meist fündig.

                    1. Hallo, danke nochmals. Ja klar, die PDO Treiber habe ich in der php.ini aktiviert.Und anschließen den IIS neu gestartet.

                      extension=php_sqlsrv_7_nts_x64.dll extension=php_pdo_sqlsrv_7_nts_x64.dll

                      Und wegen des Fehlers: Es gibt keine andere Meldung als diese:

                      Fatal error: No ODBC error was found in connect.php Das ist dann die Stelle wo PDO versucht eine Verbindung aufzunehmen:

                      $con = new PDO( "sqlsrv:server=$serverName ; Database=MyTestDB", "myuser", "mypassword");  
                      
                      Daher bin ich etwas ratlos, was die Ursache sein kann.
                      
                      Gruss
                      Werner
                      
                      1. Ja klar, die PDO Treiber habe ich in der php.ini aktiviert.Und anschließen den IIS neu gestartet.

                        Hm.

                        1. Es gibt oft mehrere php.ini. Welche geladen wird zeigt php_info().
                        2. Überprüfe auch die Pfade. Suche dazu in der PHP.ini nach etwas wie
                        extension_dir = "C:\PHP\ext"
                        

                        Sagt denn das error-log irgendwas? Meckert PHP bei Start im Terminal? Normalerweise müsste PHP sich mit error_reporting(E_ALL) beim Start darüber beschweren, dass es eine Extension nicht laden kann.

    2. Der relevante Sourcecode von PHP 7.1.14 verwendet Dinge, die ich noch nie selbst gemacht habe, von daher weiß ich nicht, wo man konkret suchen müsste.

      Der Kern scheint die darin genutzte Windows-API-Funktion CryptGenRandom() aus der Advapi32.dll zu sein.

      Die ist als "deprecated" markiert. Das wiederum ist wohl der Grund, warum die Entwickler den Code überhaupt "angefasst" haben.