Kleine Passwortabfrage per php

  • Guten Abend liebe pi Gemeinde,

    ich steuere mit einem pi1 (b+) unter wheezy div. ELRO Funksteckdosen. Hierfür habe ich einen Webserver (lighthttpd) eingerichtet um per Handy meine Dosen zu schalten. Das funktioniert soweit seit Monaten problemlos. Nun möchte ich 2-3 Funktionen in einen seperaten Admin-Bereich legen, welche nur nach Eingabe eines Passwortes angezeigt werden:

    Auszug aus der index.php welcher auf die Admin Anmeldung verlinkt:

    Code
    echo "<a href='http://192.168.178.250/login.php'><img src='http://192.168.178.250/login.png'border=\"8\" width=\"285\" / ></a>";

    Die login.php schaut folgendemaßen aus:

    Und nun zu guter letzt die admin.php:

    Nach dem ganzen Code nun zum eigentlichen Problem. Wenn ich auf den Link Anmeldung als Admin kommt brav die Kennwort-Abfrage. Tippe ich ein falsches Passwort ein springt er in die richtige else Bedingung und quittiert mit einem "Das Passwort ist falsch!". Das klappt ebenfalls problemlos. Wenn ich das Passwort richtig eingebe, sehe ich die admin.php mit den einzelnen Steckdosen, kann diese aber leider nicht schalten. Nach einem Klick auf die Dose erfolgt wieder die Ausgabe von "Das Passwort ist falsch!". Die weiter unten aufgeführten Links, welche den pi rebooten/herunterfahren funktionieren hingegen problemlos.

    Kann mir jemand von den php Profis mal einen Blick auf die admin.php werfen, wo der Schweinehund begraben ist?

    Danke u. Grüße M.

    P.S. Ich weiß, schöne Programmierung ist anders... meine Möglichkeiten sind leider etwas beschränkt, daher arbeite ich nach try and error :)

    Einmal editiert, zuletzt von Micky (10. Mai 2016 um 21:24)

  • Es gibt 2 Möglichkeiten für ein Passwordschutz:

    • Datei in separates Verzeichnis legen und .htaccess nutzen.
    • Mithilfe von $_SESSION ein unabhängiges System erstellen.

    Dein Problem hängt damit zusammen das ein erfolgreicher Login nicht gespeichert wird. Dafür nutzt man $_SESSION - also ein Cache der nur eine begrenzte Gültigkeitsspanne hat - um über mehrere PHP Dateien hinaus auf bereits festgelegte Variablen zugreifen zu können.
    Also:
    Jede PHP Datei die davon profitieren soll muss sofern noch nicht existent, "start_session();" ganz am Anfang der Datei ausführen. Nach erfolgreichem Login erzeugst du zB einen Eintrag "$_SESSION['validUser'] = true;" und prüfst dann auf allen Seiten ob das auch korrekt gesetzt wurde, falls nicht kommt die Aufforderung zum Login ....

    Beispiel:

    global.php
    [code=php]
    <?php
    if (!isset($_SESSION)) { session_start(); }

    define('TIMEOUT', 3600); // default: 60 min

    session_cache_limiter(TIMEOUT);
    ini_set("session.gc_maxlifetime", TIMEOUT);

    function loginUser($USER,$PASS) {
    $errorText='';
    $validUser=false;
    $db = db_con();
    $query = $db->query("SELECT id,user,pass FROM auth WHERE user='".$USER."'");
    while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
    if ($row['user'] == $USER AND $row['pass'] == trim(md5($PASS))) {
    $validUser = true;
    $_SESSION['old_session'] = session_name($USER);
    $_SESSION['userID'] = $row['id'];
    $_SESSION['userName'] = $row['user'];
    $_SESSION['lastVisit'] = time();
    $updatedb = $db->query("UPDATE auth SET ip='".$_SERVER['REMOTE_ADDR']."' WHERE user='".$USER."'");
    $updatedb = $db->query("UPDATE auth SET online='1' WHERE user='".$USER."'");
    $updatedb = $db->query("UPDATE auth SET lastlogin='".time()."' WHERE user='".$USER."'");
    }
    }
    if ($validUser != true) {
    $errorText = "Invalid username or password!";
    }
    if ($validUser == true) $_SESSION['validUser'] = true;
    else $_SESSION['validUser'] = false;
    return $errorText;
    }

    function logoutUser($USER="") {
    if (empty($USER) AND !empty($_SESSION['userName'])) { $USER = $_SESSION['userName']; }
    if (!empty($USER)) {
    $db = db_con();
    $updatedb = db_query("","UPDATE auth SET online='0' WHERE user='".$USER."'");
    }
    session_unset();
    session_destroy();
    header('Location: /');
    }

    function checkLogin() {
    if ((!isset($_SESSION['validUser'])) || ($_SESSION['validUser'] != true)) {
    header("Location: /index.php");
    exit();
    } elseif ($_SESSION['lastVisit'] + TIMEOUT < time()) {
    logoutUser();
    }
    }
    ?>
    [/php]

    login.php
    [code=php]
    <?php
    require_once("global.php");

    if ((!isset($_SESSION['validUser'])) || ($_SESSION['validUser'] != true)) {
    $error = '';
    if (isset($_POST['submitBtn'])) {
    // Get user input
    $username = isset($_POST['username']) ? $_POST['username'] : '';
    $password = isset($_POST['password']) ? $_POST['password'] : '';
    // Try to login the user
    $error = loginUser($username,$password);
    if ($error == '') { header('Location: /admin.php'); }
    }
    ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
    <html>
    <head>
    <title>Login</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <meta name="robots" content="DISALLOW">
    </head>
    <body style='background-image:none'>
    <div id="LoginMain">
    <!-- <div class="Logincaption">Login</div> -->
    <div id="icon">&nbsp;</div>
    <form action="" method="POST" name="loginform">
    <table width="100%">
    <tr><td>Username:</td> <td><input class="Logintext" name="username" type="text" autofocus="autofocus" placeholder="Login.."/></td> </tr>
    <tr><td>Password:</td> <td><input class="Logintext" name="password" type="password" placeholder="Pass.."/></td> </tr>
    <tr><td colspan="2" align="center"><input class="Logintext" type="submit" name="submitBtn" value="Login"/></td> </tr>
    </table>
    </form>
    <?php
    if (isset($_POST['submitBtn'])){
    ?>
    <div class="Logincaption">Login result:</div>
    <div id="icon2">&nbsp;</div>
    <div id="Loginresult">
    <table width="100%"><tr><td><br/>
    <?php
    if (!empty($error)) { echo $error; }
    ?>
    <br/><br/><br/></td></tr></table>
    </div>
    <?php
    }
    ?>
    </div>
    </body>
    </html>
    <?php
    } else { header('Location: /'); }

    ?>
    [/php]

    &quot;alt&quot;


    [code=php]
    <?php
    require_once("global.php");

    if ((!isset($_SESSION['validUser'])) || ($_SESSION['validUser'] != true)) {
    $error = '';
    if (isset($_POST['submitBtn'])) {
    // Get user input
    $username = isset($_POST['username']) ? $_POST['username'] : '';
    $password = isset($_POST['password']) ? $_POST['password'] : '';
    // Try to login the user
    $error = loginUser($username,$password);
    if ($error == '') { header('Location: /admin.php'); }
    }
    ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
    <html>
    <head>
    <title>Login</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <meta name="robots" content="DISALLOW">
    </head>
    <body style='background-image:none'>
    <div id="LoginMain">
    <!-- <div class="Logincaption">Login</div> -->
    <div id="icon">&nbsp;</div>
    <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST" name="loginform">
    <table width="100%">
    <tr><td>Username:</td> <td><input class="Logintext" name="username" type="text" autofocus="autofocus" placeholder="Login.."/></td> </tr>
    <tr><td>Password:</td> <td><input class="Logintext" name="password" type="password" placeholder="Pass.."/></td> </tr>
    <tr><td colspan="2" align="center"><input class="Logintext" type="submit" name="submitBtn" value="Login"/></td> </tr>
    </table>
    </form>
    <?php
    if (isset($_POST['submitBtn'])){
    ?>
    <div class="Logincaption">Login result:</div>
    <div id="icon2">&nbsp;</div>
    <div id="Loginresult">
    <table width="100%"><tr><td><br/>
    <?php
    if (!empty($error)) { echo $error; }
    ?>
    <br/><br/><br/></td></tr></table>
    </div>
    <?php
    }
    ?>
    </div>
    </body>
    </html>
    <?php
    } else { header('Location: /'); }

    ?>
    [/php]

    admin.php
    [code=php]
    <?php
    require_once("global.php");
    checkLogin();

    // ....admin bereich....

    ?>
    [/php]

    Ruft man einfach so admin.php auf wird durch checkLogin(); geprüft ob $_SESSION['validUser'] auf true gesetzt ist... Falls nicht wird der Benutzer auf index.php umgeleitet - kann also nicht einfach so die admin.php verwenden.
    Über die index.php müsstest du dann die login.php aufrufen lassen, einfach über einen Link o.ä. und wenn darüber ein Login erfolgreich war wird man zur admin.php weitergeleitet..

    Ich nutze hierbei MySQL zum speichern der Zugangsdaten - die entsprechenden Funktionen hab ich jetzt nicht mit gepostet.... Das kannst du aber natütlich nach belieben anpassen


    PS: Auch wenn PHP keine Einrückungen benötigt solltest du es dir trotzdem angewöhnen - denn es lässt sich dann einfach besser lesen/verstehen.

  • Hallo zusamen,
    ich würde an dieser Stelle auf jeden Fall zu der Variante mit .htaccess tendieren. Das ist für Anfänger die einzig sichere Variante und dazu noch die am einfachsten umzusetzende.
    meigrafd Dein Code bringt leider gar nichts und kann relativ einfach umgangen werden, da keinerlei Sicherung gegen SQL-Injection eingebaut ist. Da du den Code vermutlich irgendwo im Einsatz hast, sehe ich hier mal davon ab Details zu posten.

    Gruß
    Chris

    PS: Eine XSS-Lücke ist auch noch drinnen

    Einmal editiert, zuletzt von ChrisvA (11. Mai 2016 um 07:30)

  • ich würde an dieser Stelle auf jeden Fall zu der Variante mit .htaccess tendieren. Das ist für Anfänger die einzig sichere Variante und dazu noch die am einfachsten umzusetzende.

    .htaccess funktioniert aber nur mit apache2

    meigrafd Dein Code bringt leider gar nichts und kann relativ einfach umgangen werden, da keinerlei Sicherung gegen SQL-Injection eingebaut ist.

    Interessante Aussage. bringt nichts weil SQL-Injections möglich... hm... Dabei wird die Funktion des Codes nicht von möglichen SQL-Injections beeinflusst!? :-/ Wer keine SQL-Injections einschleust kann den Code wie vorgesehen nutzen und muss sich erst einloggen bevor er auf admin.php zugreifen kann..
    Wer SQL-Injections blockt kann den Code IMHO problemlos nutzen... Insofern ist "Dein Code bringt leider gar nichts" etwas überspitzt

    Aber doch, erzähl ruhig mehr Details - der Code ist nicht im Internet im Einsatz, insofern konnte das nämlich damals vernachlässigt werden.

    Würde mich wirklich interessieren wie du den PHP Code als Client insofern beeinflussen willst als dass checkLogin(); ausgehebelt wäre. Ganz so einfach wie du es hier darstellst ist das meiner Meinung nach nämlich nicht.

  • Interessante Aussage. bringt nichts weil SQL-Injections möglich... hm... Dabei wird die Funktion des Codes nicht von möglichen SQL-Injections beeinflusst!? :-/ Wer keine SQL-Injections einschleust kann den Code wie vorgesehen nutzen und muss sich erst einloggen bevor er auf admin.php zugreifen kann..
    Wer SQL-Injections blockt kann den Code IMHO problemlos nutzen... Insofern ist "Dein Code bringt leider gar nichts" etwas überspitzt

    Aber doch, erzähl ruhig mehr Details - der Code ist nicht im Internet im Einsatz, insofern konnte das nämlich damals vernachlässigt werden.

    Würde mich wirklich interessieren wie du den PHP Code als Client insofern beeinflussen willst als dass checkLogin(); ausgehebelt wäre. Ganz so einfach wie du es hier darstellst ist das meiner Meinung nach nämlich nicht.

    Bei folgender Zeile gibst du den eingegebenen Username ($USER) direkt in die Query ohne diese vorher zu escapen:

    Code
    $query = $db->query("SELECT id,user,pass FROM auth WHERE user='".$USER."'");

    Da könnte man nun alle möglich Befehle hinten dran hängen und sich so Zugang zur ganzen Datenbank verschaffen..

    Hier ganz gut erklärt: http://www.unixwiz.net/techtips/sql-injection.html

    u-4

  • Hallo meigrafd
    Entschuldige die etwas schroffe Antwort, aber leider zeigt die Erfahrung (aus nem PHP-Forum), dass funktionierender Code allzu gerne verwendet wird, auch wenn dieser unsicher ist und bei Webseiten häufig vom Internet aus erreichbar.


    Interessante Aussage. bringt nichts weil SQL-Injections möglich... hm... Dabei wird die Funktion des Codes nicht von möglichen SQL-Injections beeinflusst!? :-/ Wer keine SQL-Injections einschleust kann den Code wie vorgesehen nutzen und muss sich erst einloggen bevor er auf admin.php zugreifen kann..

    Da eine Passwortabfrage meiner Meinung nach ungebetene Besucher abhalten soll und nicht einen selbst ;), sehe ich eine Abfrage mit Sicherheitslücke als weitestgehend sinnlos an.

    Ich habe bewusst auf Details hier verzichtet, da ich vermeiden wollte, dass jemand aus dem Forum sich damit z.B. auf deiner Homepage einloggen kann und dir zunächst die Möglichkeit geben die Lücke zuvor zu beseitigen :)

    Die Lücke liegt im nicht umgesetzten Escaping bei den Parametern, bevor diese in das SQL-Statement eingesetzt werden.
    Aus

    PHP
    "SELECT id,user,pass FROM auth WHERE user='".$USER."'"[/php]
    wird, wenn man als Nutzername die Zeichenkette 
    [code]' AND FALSE UNION SELECT '0', 'root', 'd41d8cd98f00b204e9800998ecf8427e


    einsetzt (d41d8cd98f00b204e9800998ecf8427e ist der md5-Hash von einer leeren Zeichenkette)

    wird in der Datenbank folgendes abgefragt:
    [code=php]"SELECT id,user,pass FROM auth WHERE user='' AND FALSE UNION SELECT '0', 'root', 'd41d8cd98f00b204e9800998ecf8427e'"[/php]

    Das Ergebnis der Abfrage ist immer
    0 root d41d8cd98f00b204e9800998ecf8427e

    und bei einem leeren Passwort wird der Benutzer mit der ID 0 und dem Namen Root erfolgreich eingeloggt.

    Die folgenden UPDATE-Abfragen werden zwar schief laufen, soweit ich das sehe, wird das aber nicht weiter beachtet.

    Zum beheben der Sicherheitslücke müssen alle Nutzereingaben escaped werden, dafür kann man entweder konsequent die entsprechenden Funktionen nutzen, oder alle Abfragen mit Prepared Statements (https://secure.php.net/manual/de/pdo.prepare.php) ausführen und das escaping automatisch erledigen lassen. (Meiner Meinung nach ist letzteres zu bevorzugen, da ist das Risiko geringer einmal das escaping zu vergessen.)

    Zum Thema Passwörter sei noch gesagt, dass md5 hauptsächlich "gut gemeint" ist (https://secure.php.net/manual/de/faq.passwords.php). PHP bietet seit Version 5.5 eine extra API dafür, die das sicher umsetzt: https://secure.php.net/manual/de/book.password.php

    Die XSS-Lücke versteckt sich in
    [code=php]echo $_SERVER['PHP_SELF'];[/php]
    Da PHP_SELF vom Nutzer weitestgehend beliebig gesetzt werden kann. (Einfach statt index.php die Seite index.php/<was auch immer> aufrufen).

    Gruß
    Chris

    PS: Das .htaccess ist apache2 spezifisch ist hatte ich nicht bedacht, aber z.B. für ngix : http://kbeezie.com/protecting-folders-with-nginx/ , lighthttpd: http://www.cyberciti.biz/tips/lighttpd-…irectories.html

  • Das Problem bei den Injections ist dass der Angreifer erst mal wissen muss wie der PHP Code überhaupt aussieht. Bedeutet also das der Code allgemein bekannt sein muss da der Client nicht den PHP Code zu Gesicht kriegt, und das wiederum bedeutet das Angreifer nur Injections auf zB myBB o.ä. anwenden da der Code weit verbreitet und öffentlich bekannt ist... Bei solch einem kleinen Projekt müsste der Angreifer erst mal die Webseite finden wo das in der Form zum Einsatz kommt - viel Glück :D (wir sind hier weitestgehend anonym)

    Was würde es bringen vom <form> das $_SERVER['PHP_SELF'] zu verändern, also die "action" ? Dann würde beim absenden des Formulars die POST Daten nicht mehr an index.php gesendet werden sondern zB an admin.php - aber was dann? In der admin.php ist i.d.R. nichts was auf $_POST reagiert :s

    Dennoch, danke für die Hinweise ;)


  • Was würde es bringen vom <form> das $_SERVER['PHP_SELF'] zu verändern, also die "action" ? Dann würde beim absenden des Formulars die POST Daten nicht mehr an index.php gesendet werden sondern zB an admin.php - aber was dann? In der admin.php ist i.d.R. nichts was auf $_POST reagiert :

    Es gibt 2 Möglichkeiten XSS-Lücken auszunutzen, zum einen kann man die Seite verändern und so z.B. die Logindaten an einen eigenen Server senden, oder man kann Sessions von der Domain übernehmen. Einzig muss man den Nutzer dazu bringen auf einen manipulierten Link zu klicken, was bei Phishing-Mails durchaus möglich ist.

    Bei der MySQL-Injection Lücke gebe ich dir recht, wenn man den Code nicht kennt, ist das Ausnützen schwieriger. Da häufig aber die selben Fehler gemacht werden, z.B.
    [code=php]SELECT `passwd` FROM `users` WHERE user = $USER[/php] oder Abwandlungen davon, gibt es gewisse Muster, mit denen man häufig solche unsicheren Abfragen umgehen kann.

    Ich würde aber vorschlagen diese Diskussion hier jetzt erst einmal zu beenden und uns wieder auf das eigentliche Thema konzentrieren.

    Micky: Was für ein Webserver wird denn genutzt.

  • So ganz von der Hand zu weisen ist ChrisvA's Hinweis nicht. Er hat es an einem einfachen Beispiel gezeigt. Es gibt aber bedeutend mächtigere SQL-Anweisungen, die unter Umständen das gesamte System offenlegen. Aber trotzdem kann man PHP und SQL sicher machen und normalerweise steht das "Wie" auch in jedem Grundlagenbuch. Escapen ist ein Muss, beim Umgang mit PHP. Selbst wenn der Quellcode nicht bekannt ist, kann Schaden angerichtet werden. Allerdings ist es auch so, dass das alles einen gewissen Aufwand erfordert und man da als uninteressant gilt. Trotzdem, wer so wie ich die Haustür mit dem Smartphone öffnet, sollte das beachten.

  • Hallo Zusammen,

    erstmal vielen Dank für die zahlreichen Antworten... werde mich heut abend mal Zeile für Zeile durchkämpfen... SQL Injection und Co spielen keine Rolle, da dieser pi ausschließlich im internen Netzwerk (privat) angesteuert wird. Er ist von außen nicht erreichbar. Die Anzahl und das KnowHow der Nutzer diese einfache Passwortsperre ist sehr gering, daher würde dieses kleine PHP Skript ansich genügen.

    Wie gesagt, schaue ich mir eure Antworten heut abend (wenn Kind schläft) nochmal in Ruhe im Detail an und ergänze dann fehlende Angaben und gebe Feedback. Vielen Dank an dieser Stelle für eure Unterstützung und bis heut abend ...

    Grüße Micky

    P.S. Webserver ist lighthttpd.

    Einmal editiert, zuletzt von Micky (11. Mai 2016 um 18:28)

  • Nabend meigrafd,

    vielen Dank für das ausführliche Erklären deiner Skripte. Ich glaube jedoch, dass es fast zu aufwendig für die Anforderung ist. Dieser pi steuert per 433mhz div. Funksteckdosen in meinem lokalen (privaten) Netzwerk. Dieser ist auch nicht von aussen erreichbar. In diesem Admin Bereich liegen z.B. die Buttons für das Schalten von 1-2 Steckdosen, welche nicht für meine Frau/Sohn zugänglich sein sollen... Daher war mein Grundgedanke hier einfach eine kleine Passwortabfrage einzubauen... Auf die Eingabe eines Usernamen kann ich problemlos verzichten.

    Das von mir gepostete Skript funktioniert zum Teil, da nur nach Eingabe des richtigen Kennwortes die admin.php geladen wird. Ich kann auch die http Links im AdminBereich starten. Lediglich die php-Buttons für das Schalten der Dosen funktionieren zur Zeit nicht.

    Im Prinzip prüfe ich ja hier auf einfachem Weg die PW-Eingabe:

    PHP
    <?php
     $pass = $_POST['pass'];
    if ($pass == "Pi" OR $pass == "pi") {
    ....

    Alles was nun nach der geschweiten Klammer kommt, wird also nur abgearbeitet wenn die PW-Eingabe richtig war... Bei einer falschen Eingabe springt er unten in den ELSE Bereich und gibt auch aus, dass die PW-Angabe falsch war.

    Der Bezug zur config2.php funktioniert ebenfalls, da die richtigen Dosen (auch mit den richtigen Bezeichnungen) aus der config2.php geladen werden. Die Anzeige ist also zu 100% korrekt, nur der Aufruf der Schalt-Buttons klappt im Admin-Bereich nicht. Bei einem Klick darauf springt er direkt in die ELSE Ausgabe und gibt die Fehlermeldung bzgl. des Falschem Passworts aus...

    Ich vermute, dass nur die ein oder andere geschweifte Klammer nicht passt. Sicherheit/SQL Injection und Co. spielen hier in dieser Umgebung (glücklicherweise) keine Rolle).

    LG Micky
    Automatisch zusammengefügt:
    Kleine Anmerkung noch... wenn der Button zum Schalten der Dosen geklickt wird, wird folgender Link ausgeführt:

    Code
    http://ip-vom-pi/admin.php?group=01101&switch=03&action=1

    Und genau dann erfolgt die Ausgabe, dass das eingegebene Passwort angeblich falsch wäre ;( Wenn ich diesen Link direkt per http Link einbaue funktioniert das Schalten wiederum.
    Ein Teil der Buttons liegen mit der identischen Konfiguration auch im öffentlichen Bereich. Diese funktioneren ohne Probleme. Vielleicht hilft euch das ja noch...

    Vielen Dank für eure Unterstützung.

    Grüße M.

    Einmal editiert, zuletzt von Micky (11. Mai 2016 um 22:35)

  • Nabend @all,

    ich vermute, dass Problem liegt an den folgenden 3 Zeilen, welchen den Link zum Schalten der Dosen zusammen setzen:

    Code
    echo "<a href=\"?group=".$ig;
        echo "&switch=".$is;
        echo "&action=".$ia."\">";

    Mit diesem Code versucht er den Link

    Code
    http://ip-vom-pi/admin.php?group=01101&switch=03&action=1


    zu öffnen, was ja nicht funktioniert. Die Funksteckdosen im öffentlichen Bereich des WebServers werden mit dem folgendem Link geschalten, was auch funktioniert:

    Code
    http://ip-vom-pi/remote.php?group=01101&switch=03&action=1

    Wie kann ich den o.g. Link so umbauen, dass er beim Aufruf statt der admin.php die remote.php verwendet? Jemand nen Tipp?

    Grüße M.

  • Bei jedem Klick eines der Links wird die Seite und somit die admin.php PHP Datei komplett neu geladen.
    Das Problem ist denk ich, dass das Password nur ein mal der PHP Datei übergeben wird, beim absenden des Formulars sofern du in das entsprechende Input Feld etwas eingetragen hast - oder gibst du jedes mal wenn du auf einen der Button klickst das Password erneut ein?

    Also zunächst mal solltest du ganz oben am Anfang der admin.php prüfen ob $_POST['pass'] überhaupt existiert bzw gesetzt ist. Wird die Datei nämlich ohne diese Angabe aufgerufen wird jedes mal eine Fehlermeldung ins Logfile geschrieben (unknown index o.ä.).
    Dann kannst du dir das [code=php]if (isset($_GET['group'])) $nGroup=$_GET['group'];
    else $nGroup="";[/php]Konstrukt verschönern indem du entweder ein mal komplett erst $nGroup=""; usw notierst und nur falls $_GET['group'] gesetzt ist diese überschreibst - oder eine andere Schreibweise die das selbe macht aber schöner wäre:
    [code=php]
    $nGroup = isset($_GET['group']) ? $_GET['group']: "";
    $nSwitch = isset($_GET['switch']) ? $_GET['switch']: "";
    $nAction = isset($_GET['action']) ? $_GET['action']: "";
    $nDelay = isset($_GET['delay']) ? $_GET['delay']: 0;
    [/php]
    ...das sieht nicht nur schöner aus sondern lässt sich auch besser lesen wie ich finde, und ist auch kürzer als dein bisheriges Konstrukt:
    [code=php]
    if (isset($_GET['group'])) $nGroup=$_GET['group'];
    else $nGroup="";
    if (isset($_GET['switch'])) $nSwitch=$_GET['switch'];
    else $nSwitch="";
    if (isset($_GET['action'])) $nAction=$_GET['action'];
    else $nAction="";
    if (isset($_GET['delay'])) $nDelay=$_GET['delay'];
    else $nDelay=0;
    [/php]

    Dann ist sowas hier eigentlich Quatsch:
    [code=php]
    echo "<a href=\"?group=".$ig;
    echo "&switch=".$is;
    echo "&action=".$ia."\">";
    [/php]

    Solch einen Link kannst du viel besser wie folgt konstruieren:
    [code=php]
    echo "<a href=\"?group=".$ig."&switch=".$is."&action=".$ia."\">";
    [/php]...beziehungsweise kann man das auch wie folgt besser schreiben ums besser lesen zu können:
    [code=php]
    echo "<a href=\"?group=" . $ig . "&switch=" . $is . "&action=" . $ia . "\">";
    [/php]

    Allerdings frage ich mich hier wieso du $ig usw setzt aber nicht direkt mit $current[0] arbeitest? Jede Variable die du einsparen kannst verbraucht weniger RAM und benötigt weniger Verarbeitung => Schneller. Zumal $ig $is usw nicht wirklich aussagekräftig sind - sinnvolle Variable-Namen, entsprechend ihrer Funktion und so... ;)

    An der Formatierung deines Codes, und daran das du obiges ein mal nutzt dann aber wieder doch nicht, könnte man btw auch herauslesen was du blind copy&pasted hast und was von dir stammt :fies: Zb die Linkbildung ist vermutlich von dir, aber die div Zeilen danach nicht... <br> ist vermutlich ebenfalls von dir aber <br /> nicht, usw :fies:


    Aber noch mal zurück zum Anfang... Dein Problem laut Beitrag#1 ist dass das Password nur ein mal akzeptiert wird:


    Wenn ich auf den Link Anmeldung als Admin kommt brav die Kennwort-Abfrage. Tippe ich ein falsches Passwort ein springt er in die richtige else Bedingung und quittiert mit einem "Das Passwort ist falsch!". Das klappt ebenfalls problemlos. Wenn ich das Passwort richtig eingebe, sehe ich die admin.php mit den einzelnen Steckdosen, kann diese aber leider nicht schalten. Nach einem Klick auf die Dose erfolgt wieder die Ausgabe von "Das Passwort ist falsch!".
    Die weiter unten aufgeführten Links, welche den pi rebooten/herunterfahren funktionieren hingegen problemlos.

    Hier muss man sich die Links genauer anschauen.
    Die ersten Links zum Schalten von Steckdosen sind so aufgebaut dass $_GET verwendet wird, du erstellst also einen Link der an die URI (url) ?group=01101&switch=03&action=1 usw anhängt. Das wiederum wird an die aktuelle Seite übermittelt also admin.php. Beim Klick auf solch einen Link wird aber ein Password nicht erneut eingegeben und genau das ist dein Problem.
    Die anderen Links bezüglich reboot zeigen auf eine andere PHP Datei in der vermutlich keine Passwordabfrage existiert?

    Um dieses Problem zu lösen gäbe es (selbstverständlich) mehrere Möglichkeiten. Die aus meiner Sicht am einfachsten und zugleich mit weniger Aufwand verbundene, wäre wie bereits erwähnt mit $_SESSION.... Man kanns aber halt auch immer irgendwie übertreiben so von wegen Sicherheit und so :fies:

    Ich schlage dir daher vor deine admin.php wie folgt anzupassen:

    => http://codepad.org/oOJuOcnM
    [code=php]
    <?php
    if (!isset($_SESSION)) { session_start(); }

    if (!isset($_SESSION['adminpass'])) {
    if (isset($_POST['pass']) AND !empty($_POST['pass'])) {
    $pass = $_POST['pass'];
    } else {
    header("Location: login.php");
    exit();
    }

    if ($pass != "Pi" AND $pass != "pi") {
    echo "<b><center><font size=60pt> Das Passwort ist falsch! </font></center></b>";
    usleep(3000000); //Programm-Verzoegerung in Mikrosekunden: 3s
    header("Location: login.php");
    exit();
    }

    $_SESSION['adminpass'] = $pass;
    }

    require_once("config2.php");

    $nGroup = isset($_GET['group']) ? $_GET['group']: "";
    $nSwitch = isset($_GET['switch']) ? $_GET['switch']: "";
    $nAction = isset($_GET['action']) ? $_GET['action']: "";
    $nDelay = isset($_GET['delay']) ? $_GET['delay']: 0;

    $output = $nGroup.$nSwitch.$nAction.$nDelay;
    if (strlen($output) >= 8) {
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Could not create socket\n");
    socket_bind($socket, $source) or die("Could not bind to socket\n");
    socket_connect($socket, $target, $port) or die("Could not connect to socket\n");
    socket_write($socket, $output, strlen ($output)) or die("Could not write output\n");
    socket_close($socket);
    header("Location: index.php");
    }
    ?>
    <html>
    <head>
    <title>HomeControl</title>
    <link rel="stylesheet" href="resources/style.css">
    <!--[if IE]>
    <link rel="stylesheet" type="text/css" href="ie.css" />
    <![endif]-->
    <link rel="icon"
    type="image/png"
    href="resources/favicon.ico">
    <meta charset="UTF-8">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="viewport"
    content="
    height = device-height,
    width = device-width,
    initial-scale = 1.0,
    user-scalable = no ,
    target-densitydpi = device-dpi
    " />
    </head>
    <body>

    <div id="header">HomeControl</div>

    <?php
    foreach($config as $current) {
    if ($current != "") {
    $ig = $current[0];
    $is = $current[1];
    $id = $current[2];

    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Could not create socket\n");
    socket_bind($socket, $source) or die("Could not bind to socket\n");
    socket_connect($socket, $target, $port) or die("Could not connect to socket\n");

    $output = $ig.$is."2";
    socket_write($socket, $output, strlen ($output)) or die("Could not write output\n");
    $state = socket_read($socket, 2048);

    if ($state == 0) {
    $ia = 1;
    $direction="on";
    }
    if ($state == 1) {
    $ia = 0;
    $direction="off";
    }
    echo "<a href=\"?group=" . $ig . "&switch=" . $is . "&action=" . $ia . "\">";
    echo "<div class=\"entry state" . $state . "\">";
    echo "<div class=\"switch\"></div>";
    echo "<span class=\"info\">".$id."</span>";
    // echo "<span class=\"channel\">Kanal ".$ig.":".$is."</span>";
    echo "</div>\n";
    echo "</a>\n";

    }
    }

    echo "<div style='font-size: 38pt'> &nbsp;HomeControl </div>";
    echo "<div style='font-size: 28pt'> &nbsp;&nbsp;&nbsp;reboot/shutdown </div>";
    echo(" <br />\n");
    echo "<a href='http://192.168.178.250/reboot.php'><img src='http://192.168.178.250/power-an.png' border='0' width='150' /></a>";
    echo "<a href='http://192.168.178.250/shutdown.php'><img src='http://192.168.178.250/power-aus.png' border='0' width='150' /></a>";

    ?>

    </body>
    </html>
    [/php]

    Was der Anfang macht ist im Prinzip:
    - Falls noch keine Session gestartet wurde und somit $_SESSION nicht existiert, wird nun eine gestartet und bleibt für 1440 Minuten (Standard Einstellung) bestehen. Nach Ablauf der Gültigkeitsspanne wird die Session destroyed also gelöscht.
    - Falls $_SESSION['adminpass'] nicht gesetzt oder nicht existiert wird die Prüfung auf $_POST['pass'] durchlaufen.
    - Falls $_POST['pass'] gesetzt wird wird der Wert in $pass hinterlegt, falls nicht wird auf login.php weitergeleitet und das aktuelle PHP Script beendet.
    - $pass wird überprüft und falls der Wert nicht "Pi" oder "pi" lautet wird ein Text ausgegeben 3 Sekunden das Script blockiert und anschließend auf login.php weitergeleitet sowie das Script beendet.
    - Wurde das Script nicht beendet sondern weiter ausgeführt, wird $pass in $_SESSION['adminpass'] geschrieben und der Rest weiter ausgeführt.

    Meldet man sich also ein mal an wird man von login.php an admin.php weitergeleitet. War das Password richtig wird $_SESSION['adminpass'] gesetzt. Wird dann die admin.php erneut innerhalb 1440 Minuten aufgerufen (und der Browser nicht geschlossen), werden einem weiterhin alle Links angezeigt da die Session noch aktiv ist.
    Läuft die Session ab oder der Browser wird geschlossen, wird man an login.php weitergeleitet.

    Ich hoffe das war verständlich erklärt? Falls noch Fragen sind dann frag ;)

  • Hallo meigrafd,

    ganz lieben Dank für deine Hilfe. Deine Erklärungen helfen mir sehr das ganze auch nachvollziehen zu können. Ich habe deine admin.php nun eingebunden und getestet. Und was soll ich sagen? ES FUNKTIONIERT. Einen ganz lieben Dank für deine Mühe und Zeit. Würde mich freuen, wenn ich mich mal revanchieren könnte.

    Grüße M.

    P.S. Gibt es eine Möglichkeit dass TimeOut von 1.440 Minuten auch etwas zu verkürzen?

    Einmal editiert, zuletzt von Micky (12. Mai 2016 um 21:47)

  • Würde mich freuen, wenn ich mich mal revanchieren könnte.

    Du könntest mir ne Positive Bewertung geben :daumendreh2:

    P.S. Gibt es eine Möglichkeit dass TimeOut von 1.440 Minuten auch etwas zu verkürzen?

    Siehe Beitrag#2 in der global.php:

    [code=php]
    define('TIMEOUT', 3600); // default: 60 min

    session_cache_limiter(TIMEOUT);
    ini_set("session.gc_maxlifetime", TIMEOUT);
    [/php]

    Das fügst du einfach unter die session_start(); Zeile ein.

  • Nabend,

    gibt´s noch ne andere Option als den "Gefällt mir2 Button?

    Ah perfekt, die global.php hab i völlig übersehen... Danke dir.

    Liebe Grüße und nen schönen Abend,

    Micky

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!