Deze website maakt gebruik van cookies. Waarom? Klik hier voor ons privacy- en cookiebeleid. Door op akkoord te klikken of door gebruik te blijven maken van deze website geeft u aan akkoord te zijn met het gebruik van cookies.

Akkoord

Vraag & Antwoord

Webprogrammeren & scripting

Veilig login script: hoe hashen?

SHARK
12 antwoorden
  • Ik heb deze tutorial gevolgd (http://www.helpmij.nl/forum/showthread.php?p=1445264) over het maken van een veilig PHP login script, aangezien ik er zeker van wil zijn dat het ook daadwerkelijk veilig is.
    Dit ziet er behoorlijk veilig uit, en het script is ook begrijpelijk. Alleen heb ik een probleem.
    Deze tutorial wil dat je een password hebt opgeslagen in de database, maar nu is mijn vraag: hoe moet je het wachtwoord hashen voordat je het in de database stopt? Dat zijn ze er vergeten bij te schrijven volgens mij.. Ik snap namelijk niet, op welke manier het wachtwoord gehashed moet zijn als het rechtstreeks uit de database geplukt wordt, wil het matchen met het door de gebruiker van het script ingevoerde wachtwoord…
    Als ik als wachtwoord de waarde die sha1(wachtwoord…) geeft in de database zet, lukt het bijvoorbeeld niet (wachtwoord niet juist…) .

    Er staat letterlijk in de tutorial:
    [quote:2401ab3b39="tutorial"]
    Wanneer de postback gemaakt is vergelijkt de server met wat er in de database staat (wachtwoorden sla je nu WEL gecodeerd (gehashed is het goede woord eigenlijk) op), als er rijen gevonden worden is de gebruiker ingelogd en anders nog een keer proberen.
    [/quote:2401ab3b39]
    Maar [b:2401ab3b39]hoe[/b:2401ab3b39] moet het wachtwoord gecodeerd worden / op welke manier moet het gehashed worden voordat ik het in de database stop. Dat is mijn vraag…

    Iemand een idee? Mis ik iets?
    Alvast bedankt!
  • er zijn verschillende manieren:
    Je kan een eigen hash schrijven, maar dat is erg veel werk.
    of je gebruitk de standaard funtie's van php
    http://nl3.php.net/md5 (wordt veel gebruikt, gebruik liever een andere ;))
    http://nl3.php.net/manual/nl/function.sha1.php (een stuk veiliger)

    overigens kan je ook een combinatie gebruiken(erg veilig), een op registratie datum ingestelelde hash, etc, etc.

    wat ik kan zien, worden de wachtwoorden daar doormiddel van javscript (dus clientside) gehashed, dit betekent dat de wachtwoorden gehashed over het internet worden verzonden. Ik vind het [b:bc2b0f8aff]persoonlijk[/b:bc2b0f8aff] netter om het met php te doen, want dan ben je altijd zeker dat je een goeie hash krijgt, en niet als de bezoeker wat heeft aangepast, opeens een hele andere hash.
  • Ja ik snap wel hoe je de hashfunctie moet gebruiken uiteraard, met md5 en sha1 (sha1 is inderdaad de beste methode), maar mijn vraag is (tis moeilijk hem goed te formuleren, mijn excuses :) ):
    In die tutorial die ik gaf, vergelijkt het php script het postback wachtwoord met het wachtwoord uit de database. Dat wachtwoord in de database staat daar al gehashed in, als ik het goed heb begrepen. Maar wat ik nergens kan achterhalen in deze tutorial, is [i:575dfd9cb1]hoe het wachtwoord gehashed moet zijn[/i:575dfd9cb1] in de database, zodat deze met het opgestuurde wachtwoord overeenkomt. Dus moet dit bijvoorbeeld sha1(wachtwoord…) of sha1(sha1(wachtwoord…)) of sha1(md5(wachtwoord…)) zijn?? Ik heb dr al een aantal geprobeerd, maar ik snap nog steeds niet hoe je het wachtwoord in de database moet zetten (in welke vorm dus)…

    Iemand?… :(
  • het lijkt er op dat de wachtwoorden doormiddel van sha1() in de database worden opgeslagen. (tenminste als ik de code goed begrijp, want er staat nergens een snippet voor het regestreren ;))
  • [quote:7372720d81="s.Mighty"]het lijkt er op dat de wachtwoorden doormiddel van sha1() in de database worden opgeslagen. (tenminste als ik de code goed begrijp, want er staat nergens een snippet voor het regestreren ;))[/quote:7372720d81]
    Haha, je hebt gelijk, ik zat het zelf helemaal fout te doen :) Het script selecteerde het veld $rij['password'] terwijl het het veld $rij['adminpass'] moest zijn – stom foutje :wink:

    In ieder geval, nu ben ik het verder aan het uitwerken, en heb ik er dit van gemaakt:

    [code:1:7372720d81]
    <?php

    session_start();

    // Session hijacking voorkomen (dit op elke pagina waarvoor men ingelogd hoort te zijn doen !)
    if( isset( $_SESSION['huidig_ip'] ) AND $_SESSION['huidig_ip'] != $_SERVER['REMOTE_ADDR'] )
    {
    // IP-adres waarmee paginarequest gemaakt wordt is niet gelijk aan IP-adres in sessie: sessie verwijderen.
    // Geen melding tonen whatsoever, dit is waarschijnlijk een hacker die bezig is.
    session_unset();
    session_destroy();
    die();
    }

    @mysql_connect( 'localhost', 'root', '' ) or trigger_error( mysql_error() );
    @mysql_select_db( 'beunders' ) or trigger_error( mysql_error() );

    // Deze functie genereert een willekeurige string
    function genereer_string( $lengte )
    {
    srand( ( (double) microtime() ) * 1000000 );
    $string = '';

    // De parser doet irri met zoveel tekens zonder spaties achter elkaar, dus verdeel ik dit ff over meerdere regels
    $tekens = 'abcdefghijklmnopqrstuvwxyz';
    $tekens .= 'ABCDEFGHIJKLMNOPQRSTUWXYZ';
    $tekens .= '01234567890123456789';

    for( $i = 0; $i < $lengte; $i++ )
    {
    $string .= $tekens{ rand( 0, ( strlen( $tekens ) - 1 ) ) };
    }

    return $string;
    }

    if( isset( $_POST['username'], $_POST['response'], $_SESSION['challenge'] ) )
    {
    $query = "SELECT * FROM configuratie WHERE adminuser = '" . sha1($_POST['username']) . "' LIMIT 0,1";
    $result = mysql_query( $query ) or trigger_error( mysql_error() );
    if( mysql_num_rows( $result ) == 0 )
    {
    echo 'Ongeldige gebruikersnaam en/of wachtwoord bij select';
    }
    else
    {
    $rij = mysql_fetch_assoc( $result );

    // Response genereren en vergelijken met wat er opgestuurd is
    if( sha1( $rij['adminpass'] . ':' . $_SESSION['challenge'] ) != $_POST['response'] )
    {
    // Exact dezelfde melding tonen als wanneer de gebruikersnaam niet in de tabel gevonden kon worden.
    // Hier een andere melding tonen zou de hacker alleen maar inzicht geven over in hoeverre zijn hackpogingen werken.
    echo 'Ongeldige gebruikersnaam en/of wachtwoord bij matchen';
    }
    else
    {
    // Gebruiker succesvol ingelogd, gegevens opslaan in sessie enzo …
    $_SESSION['loggedin'] = TRUE;
    $_SESSION['ip'] = $REMOTE_ADDR;
    echo "ingelogd";
    }
    }
    }

    // Ik check hier pas of het IP-adres al in de sessie staat en niet bij het session hijacking gedeelte.
    // Dit omdat het IP-adres in de sessie moet staan VOORDAT er een postback gedaan wordt.
    // Nou is het in dit kleine scriptje zo dat ik het daar wel neer had kunnen zetten, omdat de challenge ook pas aan het einde
    // van het PHP deel gegenereerd wordt, maar ik weet niet hoe jij dit script exact gaat implementeren, en ik wil je er wel ff
    // op attenderen dat je erop moet letten dat een postback niet geldig is wanneer er geen IP-adres / challenge in de sessie
    // staat.
    if( isset( $_SESSION['huidig_ip'] ) == FALSE )
    {
    $_SESSION['huidig_ip'] = $_SERVER['REMOTE_ADDR'];
    }

    // Elke keer dat de pagina aangevraagd is, of er nou een postback gedaan is of niet, de challenge opnieuw genereren !
    $challenge = genereer_string( 255 );
    $_SESSION['challenge'] = $challenge;

    ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Admin Panel</title>
    <script type="text/javascript" src="sha1.js"></script>

    <script type="text/javascript">
    <!–
    function createResponse()
    {
    document.getElementById( 'response' ).value = hex_sha1( hex_sha1( document.getElementById( 'password' ).value ) + ":" + document.getElementById( 'challenge' ).value );
    document.getElementById( 'password' ).value = "";
    document.getElementById( 'challenge' ).value = "";
    return true;
    }
    //–>
    </script>
    </head>

    <body>
    <?php if (isset($_SESSION['loggedin'],$_SESSION['ip']) && ($_SESSION['ip'] == $REMOTE_ADDR) && ($_SESSION['loggedin'] == TRUE)) {
    $action = $_GET['do'];
    switch ($action) {
    case "":
    echo "welkom bij de admin panel";
    break;
    case "general":
    @include "secure/general.php";
    break;
    }
    } else {
    echo "
    <form action=\"index.php\" method=\"post\" onsubmit=\"return createResponse();\">
    <div>
    Username: <input type=\"text\" name=\"username\">
    Wachtwoord: <input type=\"password\" id=\"password\">
    <input type=\"hidden\" id=\"challenge\" value=\"".$challenge."\">
    <input type=\"hidden\" name=\"response\" id=\"response\" value=\"\">
    <input type=\"submit\" value=\"Inloggen\">
    </div>
    </form>
    ";
    }
    ?>
    </body>
    </html>
    [/code:1:7372720d81]
    Het idee is dus dat wanneer het script ingelogd is, het de sessies $_SESSION['loggedin'] en $_SESSION['ip'] aanmaakt. Hiermee wil ik nadat de gebruiker is ingelogd gaan controlleren of hij is ingelogd, op iedere beveiligde pagina.
    Helaas lijkt het erop dat de sessies niet aangemaakt worden, waaraan kan dit aan liggen??
    Daarnaast vroeg ik mij af of dit systeem veilig genoeg is. Het hoeft niet uberveilig te worden, zolang het maar lekker moeilijk te kraken is…

    Alvast bedankt weer..
  • Je kunt niet met challenge-response werken en tegelijkertijd gehashte wachtwoorden in je database hebben. Want dan wordt de hash in de database gewoon het wachtwoord. (denk daar maar eens over na :) )
  • [quote:e72ce8c135="SHARK"]Je kunt niet met challenge-response werken en tegelijkertijd gehashte wachtwoorden in je database hebben. Want dan wordt de hash in de database gewoon het wachtwoord. (denk daar maar eens over na :) )[/quote:e72ce8c135]
    Pardon? Volgens mij sluit het ene het andere niet uit, maar misschien begrijp ik je verkeerd.
    Zou je kunnen uitleggen wat je exact bedoelt met deze stelling?
  • [quote:c49e646782="Annie"][quote:c49e646782="SHARK"]Je kunt niet met challenge-response werken en tegelijkertijd gehashte wachtwoorden in je database hebben. Want dan wordt de hash in de database gewoon het wachtwoord. (denk daar maar eens over na :) )[/quote:c49e646782]
    Pardon? Volgens mij sluit het ene het andere niet uit, maar misschien begrijp ik je verkeerd.
    Zou je kunnen uitleggen wat je exact bedoelt met deze stelling?[/quote:c49e646782]
    Volgens mij is dit inderdaad niet zo hoor… Bij mij doet het systeem het nu namelijk prima, met de challenge / response.
    Maar is dit dus een veilig systeem? Vooral met de check of de gebruiker ingelogd is vraag ik me het af..
  • Een eigenschap van zo'n challenge-response systeem is dat je het originele wachtwoord moet weten. Kijk:

    - Het inlog formulier wordt naar de client gestuurd tezamen met de challenge.
    - Nadat het wachtwoord op de client is ingevuld wordt deze samen met de challenge gehasht en naar de server gezonden: de response.
    - Nu moet de server de response gaan vergelijken met de verwachte (correcte) response van de client, maar daarvoor is wel het ongehashte wachtwoord nodig.

    Het nut van het hashen van de wachtwoorden in een database is dat je de wachtwoorden niet weet, ook al heb je de complete wachtwoorden-tabel. Maar met de challenge-response heb je het echte wachtwoord nodig om de response te kunnen verifiëren.
  • En dat is dus niet juist. Kijk:

    Bij registreren stuur je username en password gehashed door naar de server. Applicatie slaat die hash op als wachtwoord. Server kent dus het password niet.

    Bij inloggen stuurt server een challenge, bijv een timestamp of een guid.

    Client hashed username en wachtwoord, combineert deze met challenge en stuurt deze gehashed terug.

    Server kan de response controleren aangezien deze alle informatie heeft: de password-username-hash en de challenge.
  • [quote:b39dbc0548="Annie"]En dat is dus niet juist. Kijk:

    Bij registreren stuur je username en password gehashed door naar de server. Applicatie slaat die hash op als wachtwoord. Server kent dus het password niet.

    Bij inloggen stuurt server een challenge, bijv een timestamp of een guid.

    Client hashed username en wachtwoord, combineert deze met challenge en stuurt deze gehashed terug.

    Server kan de response controleren aangezien deze alle informatie heeft: de password-username-hash en de challenge.[/quote:b39dbc0548]
    Waar het mij om ging was het nut van gehashte wachtwoorden: ook al heb je een kopie van de complete wachtwoorden-tabel, dan kun je nog niet inloggen op het betreffende systeem.

    Stel ik heb een systeem zoals jij dat beschrijft en ik heb een kopie van die wachtwoorden-tabel dan kan ik wél inloggen en komt het nut van de gehashte wachtwoorden te vervallen (behalve misschien dat je niet de wachtwoorden kunt lezen die de gebruiker intoetste).
    Ik ontvang een challenge van de server waarna ik met behulp van het gehashte wachtwoord en gebruikersnaam (uit de wachtwoorden-tabel) de response kan vormen. Zoals ik eerder al zei: "Want dan wordt de hash in de database gewoon het wachtwoord."

    Je kunt ook kijken naar soortgelijke protocollen zoals PPP CHAP, dit is bijna precies hetzelfde alleen dan niet over http. In de RFC (RFC 1994) van dit protocol staat bij disadvantages "Irreversably encrypted password databases commonly available cannot be used."

    Om terug te komen bij dit topic. De manier zoals beschreven door Annie is een manier, en zo is het meen ik ook in het script van Carlo geimplementeerd. Wees er wel op bedacht dat de dat de wachtwoorden in de database niet onomkeerbaar versleuteld zijn. Wanneer iemand door bijvoorbeeld een SQL-injectie een record uit je wachtwoorden-tabel weet te bemachtigen dan kan hij/zij daarmee inloggen.
  • Ik deed ook geen uitspraken over de vraag of het systeem hackbaar is wanneer je de inhoud van de DB hebt verkregen (op wat voor manier dan ook). Ik wilde alleen aangeven dat het bij challenge response wel degelijk mogelijk is om een password-hash te gebruiken in de database. Zo'n hash is dan inderdaad gewoon te gebruiken als password wanneer je de inhoud van de database hebt. Wat echter niet mogelijk is, is het wachtwoord gebruiken voor andere systemen waar het wachtwoord hetzelfde is. Je hebt immers het wachtwoord niet (tenzij het andere systeem natuurlijk gebruikmaakt van dezelfde password-hash).

    [quote:89252e2f53="SHARK"]Wanneer iemand door bijvoorbeeld een SQL-injectie een record uit je wachtwoorden-tabel weet te bemachtigen dan kan hij/zij daarmee inloggen.[/quote:89252e2f53]
    Wanneer iemand door social engineering het wachtwoord achterhaald, dan kan hij ook inloggen. Dus? Maakt dat challenge response minder bruikbaar? Ik snap het punt dat je wil maken niet.

Beantwoord deze vraag

Dit is een gearchiveerde pagina. Antwoorden is niet meer mogelijk.