SQL Injection Diskussion zu "MySQL Rückgabewert inkorrekt"


tklustig

Erfahrenes Mitglied
#2
Wie soll über die URL Leiste ein Query eingeschmuggelt werden können? Ich nehme prinzipell keine $_GET Parameter als Query-Anhang auf! Is' alles $_POST bzw. $_REQUEST
 

ComFreek

Mod | @comfreek
Moderator
#4
ALLES, was extern herkommt, kann gefaked werden.
Und es hat nicht nur etwas mit Sicherheit zu tun: du läufst auch große Gefahr, invalide SQL Queries aufzubauen, wenn die Daten etwa Single Quotes oder gar Leerzeichen enthalten. Es ist einfach semantisch inkorrekt in einen SQL Query String Daten zu interpolieren. Befehle (das Query) und Daten achtlos zu mischen sollte man normalerweise nie tun. Das führt gerade dazu, dass Daten als Befehle missbraucht werden können. Ein Beispiel von Betriebssystemen, wie die Separation unterstützt wird: In Betriebssystemen werden Seiten von Prozessen (Speicherabschnitte vereinfacht gesagt), die Daten enthalten, auch so geflagged, dass sie *nicht* ausgeführt werden können. Andersherum werden Seiten, die ausfühbaren Code enthalten, auch als read-only geflagged.


Übrigens subsumiert $_REQUEST auch $_GET, von daher stimmt (deine sowieso fehlerbehaftete) Argumentation leider auch nicht.

PS: Damit deine originale Frage nicht untergeht, habe ich mal die Beiträge in ein neues Thema verschoben.
 
Zuletzt bearbeitet:

tklustig

Erfahrenes Mitglied
#5
Ich bin wohl etwas begriffsstutzig. An einem Beispiel würde ich wohl besser kapieren, was ihr meint. Wenn ich als Abfrage nur $_POST nehme, wie könnte an dem von mir veröffentlichten Code eine SQL Injection herbeigeführt werden? Ich hab's probiert - was immer ich mittels ?=value versuche, einzuschmuggeln hat keinerlei Effekt auf den Datenbankserver. Im übrigen enthält diese Datenbank nur eine einzige Tabelle. Die Tabellen anderer Datenbanken auf dem Server entsprechen alle der dritten Normalform.
 
#6
Aus deinem Code:

$sql = 'DELETE FROM temperaturs WHERE id=' . $_REQUEST["anzahlItems"];

Da Du die empfangenen Daten direkt für eine Datenbankabfrage einsetzt, wirst Du früher oder später, aber ganz sicher irgendwann jemanden einladen, Schadcode einzuschleusen.

Ein Beispiel, wie so etwas aussehen könnte, werde ich jetzt aber aus ziemlich bekannten Gründen hier nicht veröffentlichen. Allerdings dürften dazu einige allgemeine Infos zu finden sein, wenn man sich für die Sicherheit interessiert.

Als kleiner Merksatz:
Jede Benutzereingabe ist fehler- oder schadhaft, bis eine Prüfung das Gegenteil bewiesen hat.
 

ComFreek

Mod | @comfreek
Moderator
#7
Ein Beispiel, wie so etwas aussehen könnte, werde ich jetzt aber aus ziemlich bekannten Gründen hier nicht veröffentlichen.
Warum? ;) Die Info gibt's sowieso zuhauf im Internet und ein System, dessen Sicherheit auf Unkenntnis von seiner Strukturm ist generell unsicher. ("Kerkhoff'sches Prinzip")

$_POST lässt sich halt nicht so einfach mit einem Browser bearbeiten. Entweder holst du dir ein Addon für deinen Browser (z. B. Postman) oder nutzt einfach sowas wie curl oder eine Programmiersprache mit Internetlib deiner Wahl.

Ich kann später mal ein konkretes Beispiel raussuchen.
 
#8
Ich verstehe dich wohl falsch, oder willst Du ein Beispiel bringen, wie man eine SQL-Injection o. ä. per POST durchführt ?

Dass sich $_POST nicht so einfach im Browser bearbeiten lässt dürfte gerade die, die das wollen, nicht wirklich davon abhalten, ihr Unwesen zu treiben. Und nur wegen der paar, die das tatsächlich tun, macht man sich ja die Mühe, die Scripte so sicher wie möglich zu machen.
 

tklustig

Erfahrenes Mitglied
#9
Ich möchte ein Beispiel, wie man meinen Code angreifen könnte. Ob über $_POST oder über $curl oder sonstwie ist irrelevant. Ich möchte mit meinen eigenen Augen sehen, dass jemand meine Querys manipulieren kann, egal wie...
P.S.: Der Code ist im übrigen online. Die IP wäre 77.20.7.167, der DNS Name wäre tklustig.ddns.net. Es wird nix verchlüsselt(http://). Wenn jemand nachweisen kann, dass er ungewollte Querys absetzten kann, nur zu. Ich habe ein Backup der Datenbank, die Records können gelöscht werden(was mit der Onlineversion regulär nicht funktioniert)
 
Zuletzt bearbeitet:

ComFreek

Mod | @comfreek
Moderator
#10
(was mit der Onlineversion regulär nicht funktioniert)
Das scheint eine serverseitige Sperre mit einer mir unbekannten Bedingung zu sein. Auch wenn total unsicherer Code hinter einer sicheren Sperre verankert ist, heißt das niemals, dass das System gut oder sicher ist. Durch Umbauten kann die anfängliche Sperre unbemerkt entfernt oder entkräftet werden. Und dein Skript bricht trotzdem mit einem Fehler ab, wenn Quotes Teil deiner Eingabe sind.

Ich möchte mit meinen eigenen Augen sehen, dass jemand meine Querys manipulieren kann, egal wie...
Aber wenn du uns nicht glaubst, kannst du ganz einfach nach "SQL Injection Example" googeln ;)

$sql = 'DELETE FROM temperaturs WHERE id=' . $_REQUEST["anzahlItems"];
Oder konkret: Rufe dein Skript mal mit folgendem Wert für anzahlItems auf:
Das wird in DELETE FROM temperaturs WHERE id=id resultieren, d.h. alles löschen. Alternativ könntest du auch beliebige SQL-Kommandos hinzufügen. Je nach Rechte des Benutzers kannst du so beliebige Dateien lesen, überschreiben usw.

oder willst Du ein Beispiel bringen, wie man eine SQL-Injection o. ä. per POST durchführt ?
Ja, das wollte ich.

Und nur wegen der paar, die das tatsächlich tun, macht man sich ja die Mühe, die Scripte so sicher wie möglich zu machen.
Ich möchte betonen, dass das Skript im verlinkten Thread nicht nur unsicher, sondern auch inkorrekt ist. Inkorrekt im dem Sinne, dass es eben abbricht, wenn die Eingabe Quotes o. Ä. enthält.

Übrigens empfiehlt es sich auch nicht eine öffentliche phpinfo() anzuzeigen.
 

cwriter

Erfahrenes Mitglied
#11
Ich möchte mit meinen eigenen Augen sehen, dass jemand meine Querys manipulieren kann, egal wie...
(was mit der Onlineversion regulär nicht funktioniert)
Das scheint eine serverseitige Sperre mit einer mir unbekannten Bedingung zu sein.
Das sind relativ unfaire Bedingungen, um eine SQL-Injection zu demonstrieren. Wenn du gar keinen Zugang zur Datenbank erlaubst, kann man natürlich nichts injecten. Insofern ist das dann trivial "sicher".
Es gibt aber ja auch andere Zugänge zur Datenbank, z.B. über die Datumsabfrage. Wenn da der Sourcecode verfügbar wäre, könnte man vielleicht etwas basteln.
@tklustig Magst du den Code von dataTime.php und dataAll.php hier veröffentlichen? Oder sind diese Elemente Injection-safe?
Ja, das ist ein Shortcut, aber wir haben ja auch keine kriminelle Energie, sondern wollen ein Beispiel aufzeigen. Und ich mag solche Challenges durchaus :)

Ansonsten schliesse ich mich meinen Vorrednern an: Das Internet ist böse. Hast du mal in deine /var/log/apache2/access.log geschaut? Und jetzt schau mal bei abuseipdb nach, woher diese IPs kommen.
Dazu eine ernste Warnung: phpmyadmin gehört nicht ans Netz. Wenn dein Passwort nicht stark ist, hat man damit vollen Zugriff auf deine Datenbanken, und muss sich nicht mit Injections herumschlagen. Deine Version ist immerhin modern, was das Risiko einer Sicherheitslücke senkt.
Du scheinst einen Router mit NAT vor den Pi zu schalten und einfach den Port weiterzuleiten. Das ist schon mal gut, um anderen Einfallswegen vorzubeugen.

Gruss
cwriter
 

tklustig

Erfahrenes Mitglied
#12
Injection-safe ist momentan noch gar nix. Selbstverständlich werde ich den Code veröffentlichen. Wenn es jemand gelingt, in mein System einzudringen, nur zu....Allerdings gebe ich zu Bedenken, dass ein 'normaler' Angreifer nicht über diese Infos verfügt! Der sieht letztlich nur die Anwendung, keinen Code!
P.S.: phpmyadmin werde ich demnächst online nicht mehr zur Verfügung stellen, da gehe ich mit Dir konform:sneaky:. phpinfo() bleibt!
Hier der Code von dataAll.php(die Zugriffsparameter im Konstruktor habe ich natürlich abgeändert...)
PHP:
<!Doctype html> <!-- Definition des doctype-Modus -->
<html> <!-- Definition des Stammverzeichnises -->
    <head> <!-- Definition des Kopfbereiches -->
        <meta charset="utf-8"><!-- charset[utf-8:]  definiert den deutschen Zeichensatz -->
        <meta name="msvalidate.01" content="8B12875037645A4090EE64488042FDA9" /><!--validiert die Website für Bing und Yahoo-->
        <meta name="date" content="2019-05-19T08:49:37+02:00">        <!-- Angaben, wann die Seite publiziert wurde-->
        <meta name="keywords" content="Temperatur, Analyse, Graphics">    <!-- versorgt die Spider der Suchmaschinen mit Informationen zwecks Suchbegriffen -->
        <meta name="description" content="Eine Auswertung der Datenbankdaten / Pi-Temperatursensor">    <!-- Beschreibung, die in den Suchmaschinen erscheinen soll. -->
        <meta name="robots" content="index,follow">            <!-- Links sollen mitindiziert werden //NOINDEX:Seite soll nicht aufgenommen werden//NOFOLLOW Links werden nicht verfolgt-->
        <meta name="audience" content="alle">                <!-- definiert die Zielgruppe der Website  -->
        <meta name="page-topic" content="Hobby">        <!-- Zuordnungsdefinition für die Suchmaschine -->
        <meta name="revisit-after" CONTENT="7 days">            <!-- definiert den erneuten Besuch des Spiders//hier:nach sieben Tagen  -->
        <title lang="de">Temperatur Analyse</title>     <!-- weist dem HTML-Dokument in der Registerkarte einen Namen zu -->    
        <!-- Online JQuery Bibliotheken. Werden zwar nicht benötigt, können aber auch nicht schaden... -->
        <script src="js/menus.js"></script>
        <script src="js/datetime.js"></script>
        <script src="js/Alert.js"></script>
        <script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="crossorigin="anonymous"></script>
        <link href="css/style.css" rel="stylesheet">
    </head>

    <body> <!-- Definition des Bodybereiches -->
        <div class="mainDiv">
            <div id="uhr"></div>
        </div>
        <ul>
            <li class="dropdown">
                <a href="javascript:void(0)" class="treffer_0" onclick="myFunction_0()">Home</a>
                <div class="dropdown-inhalt_0" id="auswahl_0">
                    <a href="info.php">PHP-Info</a>
                    <a href="javascript:impressum()">Impressum</a>
                    <a href="index.php">Startseite</a>
                </div>
            </li>
            <li class="dropdown">
                <a href="javascript:void(0)" class="treffer_0" onclick="myFunction_1()">Daten abrufen</a>
                <div class="dropdown-inhalt_0" id="auswahl_1">
                    <a href="showGraphics.php">Grafik erstellen</a>
                    <a href="dataTime.php">bestimmte Daten abrufen </a>
                </div>
            </li>
            <li class="dropdown">
                <a href="javascript:void(0)" class="treffer_0" onclick="myFunction_2()">Adminbereich</a>
                <div class="dropdown-inhalt_0" id="auswahl_2">
                    <a href="dataDelete.php">Daten löschen</a>
                    <a href="dataRemove.php">Duplikate entfernen</a>
                    <a href="index.php">Startseite</a>
                </div>
            </li>
        </ul>
        <script>
            function impressum() {
                alert("Programmierer &  V.i.S.d.P: Thomas Kipp\nAnschrift:\nKlein - Buchholzer - Kirchweg 25\n30659 Hannover\nMobil:0152/37389041");
            }
        </script>
    <center><h2>Daten ohne Filter</h2></center>
    <p>Diese Seite zeigt zunächst die ersten 50 Records ab erster Aufzeichnung an. Nach Betätigung des SubmitButtons werden die nächsten Records angezeigt. Die Id hat Vorrang!</p>
    <form action="<?= htmlspecialchars($_SERVER['PHP_SELF']); ?>" method="post">
        <center>
            <div id="dropdown">
                <?php
                require_once 'inc/anzeigen.php';
                echo auswahlStep(48, 48, 1500);
                ?>
            </div>
            <div id="textbox1">
                <?php
                require_once 'inc/autoloader.php';
                spl_autoload_register('classAutoloader');
                $DatabaseObject = new MySQLClass('2BeHacked', '2BeHacked', 'mysql', '127.0.0.1', '2BeHacked');
                $connection = $DatabaseObject->Verbinden();
                if (!$connection) {
                    print_r("MySQL-Aufbau ist gescheitert!<br>");
                    die();
                }
                $sql = "SELECT max(id) AS max FROM temperaturs";
                $query1 = $DatabaseObject->Abfragen($connection, $sql);
                if (is_array($query1))
                    $maxId = $query1[0]['max'];
                else {
                    print_r('!!Error!!<br>Datenbankfehler. Abbruch!');
                    foreach ($connection->errorInfo() as $item) {
                        print_r('<br>' . $item);
                    }
                    die();
                }
                ?>
                <label>Ab Id:</label>
                <input type="text" name="startId" size="30" maxlength="30" placeholder="maximal bis zu ID: <?= $maxId ?>">
            </div>
            <div id="submitDropDown">
                <label>Abfeuern!</label>
                <input class="button3" type="submit" name="submit0" value="Submit">
            </div>
            <div>
                <input type="radio" name="rad" id="dummy1" value="frontOf">vor
                <input type="radio" name="rad" id="dummy2" value="back">zurück
            </div>
            <br>
        </center>
    </form>
    <script>
        function saveContents() {
            var rbIsClicked = $("input[type='radio'][name='rad']:checked");
            if (rbIsClicked.length != 0)
                localStorage['rbIsClicked'] = rbIsClicked.attr("id");
        }
        function restoreContents() {
            var rbIsClicked = localStorage['rbIsClicked'];
            if (rbIsClicked != undefined) {
                $('#' + rbIsClicked).attr('checked', true);
            }
        }
        $("input[type='radio'][name='rad']").on("change", saveContents);
        restoreContents();
    </script>
    <?php
    $folder = getcwd();
    $datei = $folder . '/txt/dropDownID.txt';
    require_once 'inc/autoloader.php';
    spl_autoload_register('classAutoloader');
    $DatabaseObject = new MySQLClass('2BeHacked', '2BeHacked', 'mysql', '127.0.0.1', '2BeHacked');
    $connection = $DatabaseObject->Verbinden();
    if (!$connection) {
        print_r("MySQL-Aufbau ist gescheitert!<br>");
        die();
    }
    $sql = "SELECT max(id) AS max FROM temperaturs";
    $query1 = $DatabaseObject->Abfragen($connection, $sql);
    if (is_array($query1))
        $maxId = $query1[0]['max'];
    else {
        print_r('!!Error!!<br>Datenbankfehler. Abbruch!');
        foreach ($connection->errorInfo() as $item) {
            print_r('<br>' . $item);
        }
        die();
    }
    if (!empty($_REQUEST['submit0'])) {
        if (!empty($_REQUEST['startId'])) {
            $id = $_REQUEST['startId'];
            if (!is_numeric($id)) {
                ?>
                <script>
                    var alertWidth = 250;
                    var alertHeight = 200;
                    var xAlertStart = 650;
                    var yAlertStart = 200;
                    var alertTitle = "<p class='pTitle'><b>! Warnung !</b></p>";
                    var alertText = "<p class='pAlert'>Nur Zahlen werden bzgl. der Primärschlüsselabfrage akzeptiert!</p>";
                    showAlert(alertWidth, alertHeight, xAlertStart, yAlertStart, alertTitle, alertText);
                </script>
                <?php
                die();
            }
            $sql = "SELECT id,datum,uhrzeit,Temperatur_Celsius,Luftfeuchtigkeit_Prozent,created_at FROM temperaturs WHERE id>=$id LIMIT 49";
            $query2 = $DatabaseObject->Abfragen($connection, $sql);
            if (is_array($query2))
                anzeigen($query2);
            else {
                print_r('!!Error!!<br>Datenbankfehler. Abbruch!');
                foreach ($connection->errorInfo() as $item) {
                    print_r('<br>' . $item);
                }
                die();
            }
            file_put_contents($datei, $id);
            die();
        }
        $boolQuery2 = true;
        //Da Sessions hier aus unerklärlichen Gründen nicht funktionieren, wird die DropDown-Id in eine Textdatei geschrieben bzw. ausgelesen    
        $id = file_get_contents($datei);
        if (isset($_REQUEST['rad'])) {
            if ($_REQUEST['rad'] == 'frontOf') {
                $dummy = $id;
                if ($id <= 18000)
                    $id += $_REQUEST["anzahlItems"];
                else
                    $id += 2 * $_REQUEST["anzahlItems"];
                if ($id > $maxId) {
                    ?>
                    <script>
                        var alertWidth = 250;
                        var alertHeight = 200;
                        var xAlertStart = 650;
                        var yAlertStart = 200;
                        var alertTitle = "<p class='pTitle'><b>! Warnung !</b></p>";
                        var alertText = "<p class='pAlert'>Sie befinden sich am oberen Ende der Meßwerte.<br>Bitte reduzieren, anstatt erhöhen!</p>";
                        showAlert(alertWidth, alertHeight, xAlertStart, yAlertStart, alertTitle, alertText);
                    </script>
                    <?php
                    $id = $dummy;
                } else
                    file_put_contents($datei, $id);
            } else if ($_REQUEST['rad'] == 'back') {
                $dummy = $id;
                if ($id <= 18000)
                    $id -= $_REQUEST["anzahlItems"];
                else
                    $id -= 2 * $_REQUEST["anzahlItems"];
                if ($id < 0) {
                    ?>
                    <script>
                        var alertWidth = 250;
                        var alertHeight = 200;
                        var xAlertStart = 650;
                        var yAlertStart = 200;
                        var alertTitle = "<p class='pTitle'><b>! Warnung !</b></p>";
                        var alertText = "<p class='pAlert'>Sie befinden sich am unteren Ende der Meßwerte.<br>Bitte erhöhen, anstatt reduzieren!</p>";
                        showAlert(alertWidth, alertHeight, xAlertStart, yAlertStart, alertTitle, alertText);
                    </script>
                    <?php
                    $id = $dummy;
                } else
                    file_put_contents($datei, $id);
            }
        } else
            print_r('!!ERROR!! Abbruch');
    } else {
        if (file_exists($datei))
            unlink($folder . '/txt/dropDownID.txt');
        $boolQuery2 = false;
        file_put_contents($datei, '50');
    }
    if (!$boolQuery2)
        $sql = "SELECT id,datum,uhrzeit,Temperatur_Celsius,Luftfeuchtigkeit_Prozent,created_at FROM temperaturs LIMIT 49";
    else
        $sql = "SELECT id,datum,uhrzeit,Temperatur_Celsius,Luftfeuchtigkeit_Prozent,created_at FROM temperaturs WHERE id>=$id LIMIT 49";
    $query2 = $DatabaseObject->Abfragen($connection, $sql);
    if (is_array($query2))
        anzeigen($query2);
    else {
        print_r('!!Error!!<br>Datenbankfehler. Abbruch!');
        foreach ($connection->errorInfo() as $item) {
            print_r('<br>' . $item);
        }
        die();
    }
    ?>
hier der Code von dataTime.php
PHP:
<!Doctype html> <!-- Definition des doctype-Modus -->
<html> <!-- Definition des Stammverzeichnises -->
    <head> <!-- Definition des Kopfbereiches -->
        <meta charset="utf-8"><!-- charset[utf-8:]  definiert den deutschen Zeichensatz -->
        <meta name="msvalidate.01" content="8B12875037645A4090EE64488042FDA9" /><!--validiert die Website für Bing und Yahoo-->
        <meta name="date" content="2019-05-19T08:49:37+02:00">        <!-- Angaben, wann die Seite publiziert wurde-->
        <meta name="keywords" content="Temperatur, Analyse, Graphics">    <!-- versorgt die Spider der Suchmaschinen mit Informationen zwecks Suchbegriffen -->
        <meta name="description" content="Eine Auswertung der Datenbankdaten / Pi-Temperatursensor">    <!-- Beschreibung, die in den Suchmaschinen erscheinen soll. -->
        <meta name="robots" content="index,follow">            <!-- Links sollen mitindiziert werden //NOINDEX:Seite soll nicht aufgenommen werden//NOFOLLOW Links werden nicht verfolgt-->
        <meta name="audience" content="alle">                <!-- definiert die Zielgruppe der Website  -->
        <meta name="page-topic" content="Hobby">        <!-- Zuordnungsdefinition für die Suchmaschine -->
        <meta name="revisit-after" CONTENT="7 days">            <!-- definiert den erneuten Besuch des Spiders//hier:nach sieben Tagen  -->
        <title lang="de">Temperatur Analyse</title>     <!-- weist dem HTML-Dokument in der Registerkarte einen Namen zu -->    
        <!--  JQuery Bibliotheken -->
        <script src="js/jquery-1.7.1.min.js"></script>
        <script src="js/jquery-ui-1.8.17.custom.min.js"></script>
        <script src="js/menus.js"></script>
        <script src="js/datetime.js"></script>
        <script src="js/Alert.js"></script>
        <!--  CSS Bibliotheken -->
        <link href="css/style.css" rel="stylesheet">
        <link rel="stylesheet" href="css/jquery-ui-1.8.17.custom.css">
        <style type="text/css"></style>
    </head>

    <body> <!-- Definition des Bodybereiches -->
        <script>
            $(document).ready(function () {
                $('#date').datepicker({
                    showOn: 'button',
                    buttonImage: 'calendar.png',
                    buttonImageOnly: true,
                    numberOfMonths: 2,
                    showButtonPanel: true,
                    autoSize: true,
                    monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
                    dateFormat: 'dd-mm-yy'
                });
            });
        </script>
        <div class="mainDiv">
            <div id="uhr"></div>
        </div>
        <ul>
            <li class="dropdown">
                <a href="javascript:void(0)" class="treffer_0" onclick="myFunction_0()">Home</a>
                <div class="dropdown-inhalt_0" id="auswahl_0">
                    <a href="info.php">PHP-Info</a>
                    <a href="javascript:impressum()">Impressum</a>
                    <a href="index.php">Startseite</a>
                </div>
            </li>
            <li class="dropdown">
                <a href="javascript:void(0)" class="treffer_0" onclick="myFunction_1()">Daten abrufen</a>
                <div class="dropdown-inhalt_0" id="auswahl_1">
                    <a href="showGraphics.php">Grafik erstellen</a>
                    <a href="dataAll.php">alle Daten abrufen </a>
                </div>
            </li>
            <li class="dropdown">
                <a href="javascript:void(0)" class="treffer_0" onclick="myFunction_2()">Adminbereich</a>
                <div class="dropdown-inhalt_0" id="auswahl_2">
                    <a href="dataDelete.php">Daten löschen</a>
                    <a href="dataRemove.php">Duplikate entfernen</a>
                    <a href="index.php">Startseite</a>
                </div>
            </li>
        </ul>
        <script>
            function impressum() {
                alert("Programmierer &  V.i.S.d.P: Thomas Kipp\nAnschrift:\nKlein - Buchholzer - Kirchweg 25\n30659 Hannover\nMobil:0152/37389041");
            }
        </script>
    <center><h2>Daten gemäß Datum</h2>
        <p>Hier werden nach dem Push auf den Submittbutton Records ab dem gewählten Datum angezeigt.</p>
        <div>
            <center>
                <form action="<?= htmlspecialchars($_SERVER['PHP_SELF']); ?>" method="post">
                    <div>
                        <input class="feld" type=text name="date0" id="date" placeholder="Datum:" value="<?php
                        if (!empty($_REQUEST['date0'])) {
                            echo $_REQUEST['date0'];
                        }
                        ?>">
                    </div>                
                    <div>
                        <br>
                        <label>gemäß Datum anzeigen</label>
                        <input class="button3" type="submit" name="submit1" value="Submit">
                    </div>
                </form>
            </center>
        </div>
        <?php
        if (!empty($_REQUEST['submit1'])) {
            if (empty($_REQUEST['date0'])) {
                ?>
                <script>
                    var alertWidth = 250;
                    var alertHeight = 200;
                    var xAlertStart = 650;
                    var yAlertStart = 200;
                    var alertTitle = "<p class='pTitle'><b>! Warnung !</b></p>";
                    var alertText = "<p class='pAlert'>Warum erzeugen Sie unnötigen Traffic?<br>Bitte ein Datum wählen, bevor Sie einen Request abfeuern!</p>";
                    showAlert(alertWidth, alertHeight, xAlertStart, yAlertStart, alertTitle, alertText);
                </script>
                <?php
                die();
            } else {
                $strDatum = "";
                //splitte das Datumfeld anhand des Trenners(-) in ein Array
                $arrayOfDate = explode('-', $_REQUEST['date0']);
                //iteriere über das Array und setze den Datumstring so zusammen, dass die Datenbank ihn erkennt
                for ($i = 0; $i < count($arrayOfDate); $i++) {
                    if ($i != count($arrayOfDate) - 1)
                        $strDatum .= $arrayOfDate[$i] . '.';
                    else
                        $strDatum .= $arrayOfDate[$i];
                }
                //jetzt enthalt die Variable strDatum das Datum so, wie ihn die Datenbank mitunter enthält. Initialisere Datenbankabfrage
                require_once 'inc/autoloader.php';
                spl_autoload_register('classAutoloader');
                $DatabaseObject = new MySQLClass('2BeHacked', '2BeHacked', 'mysql', '127.0.0.1', 'temperatur');
                $connection = $DatabaseObject->Verbinden();
                if (!$connection) {
                    print_r("MySQL-Aufbau ist gescheitert!<br>");
                    die();
                }
                $sql = "SELECT datum FROM temperaturs;";
                $query1 = $DatabaseObject->Abfragen($connection, $sql);
                if (is_array($query1)) {
                    //Iteriere über das Array(query1) und überprüfe, ob strDatum in der Datenbank enthalten ist
                    for ($i = 0; $i < count($query1); $i++) {
                        //Sofern der Wert gefunden wurde, weise ihn der Session zu und verlasse die Schleife
                        if ($strDatum == $query1[$i]['datum']) {
                            $datum = $query1[$i]['datum'];
                            break;
                            //andernfalls setze die Session auf 1
                        } else
                            $datum = 1;
                    }
                } else {
                    print_r("Fehler bei der Datenbankabfrage!");
                    die();
                }
                //Sofern der Wert nicht gefunden wurde, benachrichtige den User
                if ($datum == 1) {
                    ?>
                    <script>
                        var alertWidth = 300;
                        var alertHeight = 150;
                        var xAlertStart = 650;
                        var yAlertStart = 200;
                        var alertTitle = "<p class='pTitle'><b>! Warnung !</b></p>";
                        var alertText = "<p class='pAlert'>Das angeforderte Datum konnte nicht gefunden werden. Suchen sie ggf. erneut mit einem anderen Datum!</p>";
                        showAlert(alertWidth, alertHeight, xAlertStart, yAlertStart, alertTitle, alertText);
                    </script>
                    <?php
                } else {
                    require_once 'inc/anzeigen.php';
                    $sql = "SELECT id,datum,uhrzeit,Temperatur_Celsius,Luftfeuchtigkeit_Prozent,created_at FROM temperaturs WHERE datum='$datum' LIMIT 49";
                    $query2 = $DatabaseObject->Abfragen($connection, $sql);
                    if (is_array($query2))
                        anzeigen($query2);
                    else {
                        print_r('!!Error!!<br>Datenbankfehler. Abbruch!');
                        foreach ($connection->errorInfo() as $item) {
                            print_r('<br>' . $item);
                        }
                        die();
                    }
                }
            }
        }
        ?>
 
Zuletzt bearbeitet:

cwriter

Erfahrenes Mitglied
#13
Selbstverständlich werde ich den Code veröffentlichen.
Sehr nett :)

Allerdings gebe ich zu Bedenken, dass ein 'normaler' Angreifer nicht über diese Infos verfügt! Der sieht letztlich nur die Anwendung, keinen Code!
Das ist wahr, aber ein "echter" Angreifer schert sich auch nicht um Internetanschlusssperren. Die Probieren einfach mal durch und haben dafür ihre Programme, die alles automatisch testen, oft in Botnets. Wenn da ein Anschluss gesperrt wird, juckt die das nicht.

Wenn es jemand gelingt, in mein System einzudringen, nur zu
Also mit SQL-Injections sehe ich hier ziemlich schwarz.

Bei der DataAll.php prüfst du, ob die Eingabe numerisch ist. SQL commands werden somit gar nicht weitergeleitet, obwohl du die $id aus startID direkt übergibst.

Bei der DataTime.php benutzt du zwar die Datenbank, wie man sie nicht benutzen soll (99% der Arbeit macht hier PHP in linearen Suchen, welche wahrscheinlich sehr viel langsamer sind als MySQL mit Indices / Sortierung, geschweige denn der Lokalität. (Siehe SQL WHERE).

Aber immerhin ist es so sicher vor Injections, da selbst das $datum, das du in die Query einsetzt, aus der Datenbank selbst und nicht aus dem Input kommt.

Also gewinnst du diese Runde, und dein Code ist "sicher" vor Injections: Mal durch manuelles Abschalten, mal durch nicht-Übergeben der Parameter an die Datenbank.

Das ist etwas doof, denn so fehlt die Schockwirkung. :(
Das Problem ist: Irgendwann machst du einen Fehler, wo Injections möglich sind. Dein Löschformular z.B.
Es falsch zu lernen gibt schlussendlich mehr Probleme, da du es wieder korrigieren musst. ComFreek hat ja schon ein Beispiel gemacht, was aber eigentlich keine echte Injection ist.

Eine echte Injection, welche du bei dir lokal ausprobieren könntest, wäre diese hier:
Code:
; INSERT INTO temperaturs(Temperatur_Celsius) VALUES (1337);
(Einfach in das Feld einfüllen. Wenn du keine Defaults gesetzt hast, musst du ID, Datum etc. noch mit dazugeben, aber ich denke, das zeigt das Problem schön genug: Man könnte damit irgendwelche Werte einfügen: Das Semikolon terminiert die Abfrage nach IDs, dann kommt ein eigenes Input-Statement, das auch mit dazu ausgeführt wird).
Eingesetzt dann hier:
PHP:
$sql = 'DELETE FROM temperaturs WHERE id=' . $_REQUEST["anzahlItems"];
Deine Maxlength im HTML-Teil kann mit mit den Entwicklertools einfach auf 3000 hochschrauben, ist also kein Hindernis.

Kleine Geschichtsstunde: Früher hatte man (wie du jetzt auch) tatsächlich mit Funktionen auf Injections geprüft, mysql_escape (das hatte einen Bug, dann hiess es mysql_real_escape) und später mysqli_real_escape, welches die Inputs auf Non-SQL-Specialchars reduzierte. Das Problem dabei: Man musste immer daran denken. PDO ist viel einfacher, macht alles automatisch, und ist bei grösseren Anfragen oft schneller als das alte Stringbauen.

TL;DR: In deinem Fall gibt es keine angreifbaren Statements. Vor allem, weil du die Datenbanken extrem unkonventionell nutzt.

Gruss
cwriter
 
#14
Ich habe mich jetzt nicht durch den Code gewühlt, denn @cwriter hat das wohl schon gründlich gemacht :)

Worum es aber eigentlich ging und noch immer geht:

1. $_POST (und natürlich auch $_REQUEST und überhaupt erstmal alle Superglobalen) kann gefaked werden.
Und selbstverständlich laden solche Konstrukte wie

$sql = 'DELETE FROM temperaturs WHERE id=' . $_REQUEST["anzahlItems"];

geradezu dazu ein, sich an der DB zu vergreifen. Dabei meine ich die generelle Vorgehensweise des Verwendens von ungeprüften Benutzereingaben und nicht nur speziell diesen einen Befehl.

2. In einfachen Projekten, wo man die "gefährlichen" Stellen an einer Hand abzählen kann, mag das noch zu überblicken sein. Wenn es mal richtig viel wird, wirst Du, @tklustig, mal an den Punkt kommen, wo Du unsicher bist, ob Du wirklich alle kritischen Stellen adäquat behandelt hast. Da ist es schon beruhigend, wenn man sich nicht erst auf solche Sachen eingelassen, sondern gleich den sichere(re)n Weg eingeschlagen hat.

3. Das beliebteste Ziel - zumindest sagen das meine Logs - ist noch immer wordpress. Das gibt es schon so lange, ist so bekannt und so oft eingesetzt, dass man der Meinung sein müsste, dass die Jungs und Mädels das absolut sicher bekommen haben. Doch wenn das so wäre, gäbe es wohl kaum so viele Angriffsversuche auf das System.

4. Eigentlich sollte es keine Diskussion bedürfen, ob man eine sichere oder eine einfache Variante verwendet. Aber jeder wie er mag.
 

tklustig

Erfahrenes Mitglied
#15
Der Tenor Eurer Statements, so habe ich es zumindest verstanden, ist der, dass Usereingaben niemals ungeprüft an die Datenbank weitergereicht werden sollten, d.h., sie sollten nicht in Querys übernommen werden. Bezogen auf das Query:
PHP:
$sql = 'DELETE FROM temperaturs WHERE id=' . $_POST["anzahlItems"];
Wie wäre die Injection sichere Vorgehensweise? Da ich überwiegend mit dem Framework yii2 programmiere, habe ich mir bisher darüber keinerlei Gedanken gemacht, da Datenbankabfragen nicht mehr über die Formulierung von Querys durchgeführt werden. Da ginge da so:
PHP:
$this->findModel($id)->delete($modelView->anzahlItems);
 

tklustig

Erfahrenes Mitglied
#17
Genau so ist es. Eine Applikation, die mit dem MVC Framework yii2 entwickelt wurde ist SQL Injection safe. Dennoch verbleibt die Frage im Raum, wie ich obiges Query auf Basis der PDO Klasse ohne Verwendung von yii2 Injection safe codiere?
 

ComFreek

Mod | @comfreek
Moderator
#18
Eine Applikation, die mit dem MVC Framework yii2 entwickelt wurde ist SQL Injection safe.
So allgemein würde ich das nicht unterschreiben. Es gibt immer Methoden, ein rohes SQL Query mit Frameworks abzusetzen. Eben weil man manchmal explizit ORM umgehen möchte. Außerdem, selbst wenn du ORM benutzt, könnten z. B. LIKE-Anfragen gefährlich sein. Denn bei LIKE musst du selbst bei Prepared Statements den ganzen String übergeben, z.B.:

PHP:
// Eine Art Pseudocode, ich kenn die genaue API nicht auswendig
$preparedStatement = prepare("SELECT * FROM table WHERE x LIKE :str");
$preparedStatement->bind(":str", "%" . $_GET['username'] . "%")->run();
Hier könnte es trotzdem noch zu einer Sicherheitslücke kommen, wenn $_GET['username'] Prozentzeichen enthält. (Beachte: Auch Verletzungen von Businessregeln können Sicherheitslücken darstellen. Auch wenn du an sich keine Tabellen löschen kannst, so könntest du bestimmte Businessregeln umgehen!)

Dennoch verbleibt die Frage im Raum, wie ich obiges Query auf Basis der PDO Klasse ohne Verwendung von yii2 Injection safe codiere?
PHP: Prepared Statements und Stored Procedures - Manual
 

Neue Beiträge