Domanda

<?php
session_start();

include("connect.php");

$timeout = 60 * 30;
$fingerprint = md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);

if(isset($_POST['userName']))
{
    $user = mysql_real_escape_string($_POST['userName']);
    $password = mysql_real_escape_string($_POST['password']);
    $matchingUser = mysql_query("SELECT * FROM `users` WHERE username='$user' AND password=MD5('$password') LIMIT 1");
    if (mysql_num_rows($matchingUser))
    {
        if($matchingUser['inactive'] == 1)//Checks if the inactive field of the user is set to one
        {
            $error = "Your e-mail Id has not been verified. Check your mail to verify your e-mail Id. However you'll be logged in to site with less privileges.";
            $_SESSION['inactive'] = true;
        }
        $_SESSION['user'] = $user;
        $_SESSION['lastActive'] = time();
        $_SESSION['fingerprint'] = $fingerprint;
    }
    else
    {
        $error = "Invalid user id";
    }
}
if ((isset($_SESSION['lastActive']) && $_SESSION['lastActive']<(time()-$timeout)) || (isset($_SESSION['fingerprint']) && $_SESSION['fingerprint']!=$fingerprint)
     || isset($_GET['logout'])
    )
{
    setcookie(session_name(), '', time()-3600, '/');
    session_destroy();
}
else
{
    session_regenerate_id(); 
    $_SESSION['lastActive'] = time();
    $_SESSION['fingerprint'] = $fingerprint;
}
?>

Questa è solo la versione modificata di http://en.wikibooks.org/wiki/PHP_Programming / User_login_systems

Cosa fa setcookie(session_name(), '', time()-3600, '/'); qui?

Ecco un bug: Uso questo modulo di accesso:

<?php 
   if(!isset($_SESSION['user']))
    {
        if(isset($error)) echo $error;
           echo '<form action="' . $_SERVER["PHP_SELF"] . '" method="post">
        <label>Username: </label>
        <input type="text" name="userName" value="';if(isset($_POST['userName'])) echo $_POST["userName"]; echo '" /><br />
        <label>Password: </label>
        <input type="password" name="password" />
        <input type="submit" value="Login" class="button" />
        <ul class="sidemenu">
        <li><a href="register.php">Register</a></li>
        <li><a href="forgotPassword.php">Forgot Password</a></li>
    </ul>
    </form>';
    }
    else
    {
        echo '<ul class="sidemenu">
        <li>' . $_SESSION['user'] . '</li>
        <li><a href="' . $_SERVER["PHP_SELF"] . '?logout=true">Logout</a></li>
        </ul>';
    }
?>

Il bug è che quando eseguo il logout, la pagina rimane la stessa, ovvero il modulo di login non viene visualizzato ma vengono mostrati lo stesso logout e lo stesso utente. Quando aggiorno la pagina, diventa normale.

È stato utile?

Soluzione

Quando esci, per prima cosa stai accodando la distruzione del cookie (avverrà dopo l'invio della risposta), quindi immediatamente dopo, renderizzando la tua pagina. Il browser non ha alcuna possibilità di eliminare il cookie prima del rendering e le tue $_SESSION variabili sono ancora attive.

I documenti di PHP dicono di session_destroy:

  

session_destroy () distrugge tutti i dati associati alla sessione corrente. Non disattiva nessuna delle variabili globali associate alla sessione né disattiva il cookie di sessione.

Una soluzione è, invece di distruggere la sessione e il cookie, semplicemente annullare l'impostazione delle variabili che causerebbero l'autenticazione:

unset($_SESSION['user']);
unset($_SESSION['lastActive']);
unset($_SESSION['fingerprint']);

Solo una nota: suggerirei di dividere il codice in funzioni. Ciò lo renderebbe molto più organizzato e leggibile (e riutilizzabile se fai le cose nel modo giusto).

Altri suggerimenti

Alcune note di sicurezza:

if($matchingUser['inactive'] == 1)

è meglio scritto come

if(!$matchingUser['inactive'])

Perché se lo schema del database cambia (ad es. ora è un numero intero per indicare un certo tipo di attività (che è una cattiva progettazione, secondo me: un elenco farebbe meglio)) il tuo codice avrebbe problemi.

Naturalmente, questo è un doppio negativo, che può essere meno leggibile. Meglio sarebbe:

if($matchingUser['isactive'])

O anche:

if($matchingUser->isActive())

supponendo che tu crei una classe utente, ecc. ecc.

Per ogni evenienza, utilizzare o require o require_once ove necessario (preferibilmente quest'ultimo se connect.php contiene dichiarazioni di funzioni).

Memorizza l'ID utente nella variabile di sessione anziché nel nome utente. È possibile consentire a un utente di modificare il proprio nome in un secondo momento e i dati della sessione non sarebbero validi (almeno ['user'] sarebbe comunque). È anche più veloce trovare un record di database in base all'ID (chiave primaria, unica) rispetto al nome utente (forse indicizzato, stringa).

Calciarmi dopo 30 minuti è davvero fastidioso. Non sei l'unico sito a cui vado e potrei rivisitare più tardi dopo aver fatto un po 'di lavoro (se vengo chiamato per fare qualcosa, per esempio, o fare una pausa pranzo).

Usa htmlspecialchars per aiutare a prevenire XSS.

Non è necessario utilizzare $_SERVER['PHP_SELF'] qui:

<a href="' . $_SERVER["PHP_SELF"] . '?logout=true">

Basta scrivere senza di essa:

<a href="?logout=true">

Quando l'utente POST qualcosa, assicurati di reindirizzarli (TODO: nota come). Altrimenti, il pulsante Indietro dell'utente potrebbe causare un nuovo POST dei dati (che probabilmente non è quello che vuoi!).

$matchingUser['inactive'] non verrà mai impostato, poiché non si ottengono i dati effettivi dal proprio db con mysql_fetch_assoc().

Versione modificata:

$matchingUser = mysql_query("SELECT * FROM `users` WHERE username='$user' AND password=MD5('$password') LIMIT 1");
if (mysql_num_rows($matchingUser))
{
    $matchingUserData = mysql_fetch_assoc($matchingUser);
    if($matchingUserData['inactive'] == 1) //Checks if the inactive field of the user is set to one
    {
        $error = "Your e-mail Id has not been verified. Check your mail to verify your e-mail Id. However you'll be logged in to site with less privileges.";
        $_SESSION['inactive'] = true;
    }

$_SERVER['REMOTE_ADDR'] potrebbe cambiare se l'utente si trova dietro un proxy.

MD5 è un mezzo piuttosto debole per crittografare la password e ci sono molti modi per aggirarla. È utile, tuttavia, che sia stato impostato con l'indirizzo IP, ma gli IP cambiano sicuramente un po '.

Inoltre, non hai nulla lì dentro per assicurarti che qualcuno non colpisca ripetutamente il sistema per rompere la password per un utente.

G-Man

Usa il sale insieme a MD5 o sha1. Quello che uso per generare la password e per verificare la password al momento dell'accesso.

function generateHash($plainText, $salt = null)
{
    define('SALT_LENGTH', 9);
    if ($salt === null)
    {
        $salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
    return array($salt, sha1($salt . $plainText) );
    }
    else
    {
        $salt = substr($salt, 0, SALT_LENGTH);
    return sha1($salt . $plainText);
    }

}

Per $ plainText, invia la variabile password.

Quando si desidera generare un nuovo hash, verranno restituiti 2 valori. Il primo valore si chiama 'salt' e il secondo valore è la password crittografata. Memorizzarli entrambi nel database.

Quando qualcuno tenta di accedere al tuo sito e desideri verificare, invia la loro password e la variabile salt alla funzione e restituirà un hash. Quindi puoi confrontarlo con il valore memorizzato nel database, per verificare se la password inserita dall'utente è corretta.

Sembra a posto. setcookie(session_name(), '', time()-3600, '/') elimina sostanzialmente il cookie impostando l'ora prima dell'ora corrente.

In questo caso devi assicurarti che le impostazioni del tuo server siano corrette affinché mysql_real_escape_string funzioni correttamente. In questo caso, il tuo codice presuppone che le virgolette magiche siano disattivate mentre trovo spesso che molti server lo abbiano abilitato. Probabilmente dovresti verificare se get_magic_quotes_gpc() restituisce vero o falso per vedere se le impostazioni del server stanno automaticamente sfuggendo alle stringhe per te.

Il codice sembra sicuro ma suggerirei di cercare un nuovo modo di eseguire query MySQL: DOP . Ciò consente query con parametri.

Puoi usare questo metodo descritto da Nate Abele migliorare l'affidabilità delle informazioni utilizzate per creare l'impronta digitale.

  

Cosa significa setcookie (session_name (), '', time () - 3600, '/');

Sembra che cancelli il vecchio cookie di sessione, impostando una stringa vuota su di esso e impostando un tempo di scadenza nel passato. Non sono sicuro del motivo per cui l'autore abbia utilizzato entrambi i metodi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top