Bu kod güvenli mi?

10 Cevap php
<?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;
}
?>

Bu http://en.wikibooks.org/wiki/PHP_Programming/User_login_systems sadece değiştirilmiş versiyonu

setcookie(session_name(), '', time()-3600, '/'); Burada ne yapar?

Here's a bug: I use this login form:

<?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>';
    }
?>

Bug ben çıkış yaparken, sayfa açma formu görünmüyor, yani aynı kalır ama aynı çıkış ve kullanıcı gösterilir olmasıdır. Ben sayfayı yenileyin zaman, normal olur.

10 Cevap

Çıkış yaptığınızda, ilk olarak, sayfanızı render, sonra hemen sonra, queuing çerez imha (Yanıt gönderildikten sonra ortaya çıkar) vardır. Tarayıcı render önce çerezi silmek için hiçbir şansı var, ve $_SESSION değişkenler hala hayatta.

PHP dokümanlar söylüyorlar yaklaşık session_destroy:

session_destroy () geçerli oturum ile ilişkili tüm verileri yok eder. Bu oturumda, ya da unset oturum tanımlama ile ilişkili küresel değişkenlerin herhangi yoketmek değil.

Bir çözüm yerine, oturum ve çerez yok etme, için, sadece unset kimlik doğrulaması neden olur değişkenler:

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

Sadece bir not: Ben fonksiyonları kodunuzu bölme öneririz. (Eğer doğru şeyler yaparsanız ve tekrar kullanılabilir) Bu çok daha organize ve okunabilir yapar.

Bazı güvenlik notları:

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

Daha iyi olarak yazılır

if(!$matchingUser['inactive'])

Senin kod sorunları olurdu: veritabanı şema değişiklikleri (bir numaralandırma yapmak daha iyi olurdu) örneğin benim görüşüme göre, kötü bir tasarım faaliyeti belirli bir tür (belirtmek için şimdi bir tam sayı) Çünkü eğer.

Tabii ki, bu daha az okunabilir olabilir ki, bir çift negatif. Daha iyi olurdu:

if($matchingUser['isactive'])

Ya da:

if($matchingUser->isActive())

vb bir kullanıcı sınıfı, vb oluşturmak varsayarak

Sadece durumunda, kullanmak veya require veya require_once gerektiğinde (tercihen ikincisi connect.php işlev bildirimleri içeriyorsa).

Yerine kullanıcı adı oturum değişkeni kullanıcının kimliğini saklamak. Orada bir kullanıcı daha sonra onun adını değiştirmek sağlayacak bir olasılık olduğunu ve oturum verileri (en az ['user'] olur, neyse) geçersiz olacaktır. Bu (belki endeksli string) adı tarafından daha ID (benzersiz birincil anahtar) tarafından bir veritabanı kaydı bulmak için de daha hızlı.

30 dakika sonra bana tekme gerçekten sinir bozucudur. Sen ben gitmek yalnızca site değiliz, ve ben (örneğin, bir şey yapmak için çağırdı alırsanız, ya da bir öğle yemeği mola) bazı işler yaptıktan sonra daha sonra tekrar olabilir.

htmlspecialchars XSS önlemek için kullanın.

: $_SERVER['PHP_SELF'] burada kullanmak gerek yok

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

Sadece onsuz yazmak:

<a href="?logout=true">

Kullanıcının mesajlarını şey, (: nasıl not TODO) onları yönlendirmek için emin olun. Aksi takdirde, kullanıcının geri düğmesi verilerin yeniden POST neden olabilir (muhtemelen ne istediğiniz değil ki!).

Eğer mysql_fetch_assoc() ile db gelen gerçek veri alamadım gibi $matchingUser['inactive'], set asla.

Değiştirilmiş versiyonu:

$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;
    }

Kullanıcının bir proxy arkasında ise $_SERVER['REMOTE_ADDR'] değiştirebilir.

Use salt along with MD5 or sha1. What I use to generate the password and to check for password upon login.

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);
    }

}

$ Plaintext için, parola değişken göndermek.

Yeni bir karma oluşturmak istediğinizde, bu 2 değerlerini döndürecektir. İlk değer 'tuz' olarak adlandırılır ve ikinci değer şifreli parola olur. Veritabanına ikisi saklayın.

Biri sitenize giriş için çalışır, ve kontrol etmek istediğiniz zaman, işlevine şifrelerini ve tuz değişkeni göndermek ve bir karma dönecektir. Sonra kullanıcı tarafından girilen şifre doğru olup olmadığını kontrol etmek, veritabanında saklanan değeri ile karşılaştırabilirsiniz.

Bu güzel görünüyor. setcookie(session_name(), '', time()-3600, '/') aslında şimdiki zaman için önce zaman ayarı tarafından çerez siler.

Bu durumda emin mysql_real_escape_string düzgün çalışması için size sunucusu ayarlarının doğru olduğunu yapmak zorunda. Bu durumda, kod sık sık birçok sunucu etkinleştirilmiş olduğunu bulmak ise Sihirli Tırnaklar kapalı olduğunu varsayarak. Muhtemelen get_magic_quotes_gpc() sunucusu ayarlarını otomatik olarak sizin için dizeleri kaçan olup olmadığını görmek için true veya false döndürür olmadığını görmek için kontrol edilmelidir.

Kod güvenli görünüyor ama ben MySQL querys yapmanın yeni bir yolu içine bakarak öneririz: PDO. Bu parametreli sorgular için izin verir.

MD5 şifresini şifrelemek için oldukça zayıf bir araçtır ve bunu aşmanın birçok yolu vardır. Bu IP adresi ile o kurulum var ama IP'leri kesinlikle biraz değiştirmek olduğunu, ancak yardımcı olur.

Ayrıca, birisi bir kullanıcı için şifre kırmak için defalarca sistemini vurmak değil emin olmak için orada bir şey yok.

G-Man

Sen this method described by Nate Abele parmak izi oluşturmak için kullanılan bilgilerin güvenilirliğini artırmak için kullanabilirsiniz.

Ne yapar setcookie (oturum_ismi (),'', time () -3600, '/');

Bunun için bir boş dize ayarlayarak ve geçmişte bir sona erme zamanı ayarlayarak, eski oturum çerezi siler gibi görünüyor. Yazar olsa da, her iki yöntem de kullanılan neden emin.