2011-11-07 61 views
0

我編碼了我的第一個會話系統。問題如下。有關會議的幾個問題

// INDEX.PHP 
    include("db.php"); // this file starts session with session_start(); also changes the default session name 

    if($_POST['login']){ $login = escape($_POST['login']); } 
    if($_POST['password']){ $password = escape($_POST['password']); } 

    if(isset($login) && isset($password)){ // LOGIN ATTEMPT 

    // check for brute force attacks 
    $btime = $time-600; // 10 minutes 
    $pull = $DB->query("SELECT * FROM logins WHERE user='$login' AND time>$btime"); 
    if($DB->num_rows($pull) > 5){ // more than 10 tries in the last 10 minutes 


      $error = "Too many login attempts have been made with this login. "; 
    // maybe lock the account for x hours 

     }else{ 

     // AUTHENTICATE 
     $sql = $DB->query("SELECT * FROM users WHERE user='$login' AND password='$password'"); 
     if($DB->n 

um_rows($sql) == 1){ // AUTHENTICATED 
    $user = $DB->fetch_array($sql); 
    $ok = 1;  
      session_regenerate_id(); 
      $_SESSION['userid'] = $user['id']; 
      $_SESSION['agent'] = md5($_SERVER['HTTP_USER_AGENT']); 
      $_SESSION['idle'] = $time; 
      header("Location: welcome.php"); // REDIRECT TO USER AREA 

    }else{ // NOT AUTHENTICATED 
     $ok = 0; 
     $error = "Wrong pass or login."; 
    } 
    // log all attempts (removed) 
    } 
    } 

功能,檢查會話:

function checksession(){ 
    global $DB, $time; 

    if($_SESSION['userid'] > 0){ 

     $userid = intval($_SESSION['userid']); 
     $user = $DB->fetch("SELECT * FROM users WHERE id=$userid"); 
     $idle = $time-$_SESSION['idle']; 

     if(!$user){ header("Location: index.php"); } 
    elseif($_SESSION['agent'] != md5($_SERVER['HTTP_USER_AGENT'])){ session_destroy(); header("Location: ".$site."index.php"); } // check user agent 
    elseif($idle > 7200){ session_destroy(); header("Location: ".$site."index.php"); } // destroy session if no activity for 2 hours 
    else{ 
     $_SESSION['idle'] = $time; 
    } 
    }else{ header("Location: ".$site."index.php"); // user id not set 
    } 
    return $userid; 
} 

註銷功能

function logout(){ 
session_destroy(); 
header("Location: index.php"); 
} 

它工作正常,但它並不完美。

問題:

  • 當我做session_regenerate_id();會話ID發生變化,但舊會話仍保持活動狀態。所以這非常沒用。我在安全級別發生變化時執行此操作。我也考慮過定期做。我正在使用PHP 5.3.6的MAMP。

  • 如果用戶不想破壞會話並簡單地關閉瀏覽器,會話文件似乎永遠留在系統中。我想知道如何1)使會話在X小時後死亡,即使用戶處於活動狀態。 2)如果用戶閒置會使會話死掉(有點像我現在擁有的系統,但是來自系統的一方)。

  • 我注意到,如果我在修改會話cookie之前登錄相同的會話文件,除了使用用戶信息的新重新生成的id以外,還會保存在會話文件文件夾(空)中。不知道這個,只是覺得很奇怪。

  • 我是否正確銷燬會話?

該網站應該有一個相當高的安全等級,因爲真錢會涉及到用戶帳戶。我正考慮在會話中保存頁面點擊次數,如果發生更改,則意味着其他人已將會話結束。會議然後將被殺死。

回答

1

session_regenerate_id():會話ID實際上只是大的隨機數。 PHP實現它們的會話ID是非常隨機的,以防止人們簡單地猜測或增加有效的會話ID。儘管如此,如果攻擊者獲得有效的會話ID,他們可以「劫持」你的會話。更改有效會話的會話標識實際上沒有解決這個問題。您需要添加另一層安全性,可能是將客戶端的IP地址與會話ID相關聯。這樣,您幾乎可以發佈會話ID(不推薦),但是攻擊者無法利用它,因爲他們無法使用欺騙IP地址完成TCP連接。

如果用戶不想破壞會話並簡單地關閉瀏覽器,會話文件似乎永遠留在系統中。 會話cookie將保留在客戶端計算機上,直到他的瀏覽器認爲它已過期。我認爲默認時間是24分鐘。會話文件將保留在服務器上,直到它被PHP的會話垃圾收集器收集。

我想知道如何1)使會話在X小時後死亡,即使用戶處於活動狀態。這可以通過PHP的配置參數來控制:session.gc-maxlifetime。請注意,您還需要更改其他session.gc選項以強制清除。 See this also

這也適用於用戶閒置的情況。

編輯:我看錯了。這不適用於活躍用戶。對於活躍的用戶,您必須手動記錄他們已登錄多久並「註銷」。

我注意到,如果我修改會話cookie之前登錄相同的會話文件獲取保存在會話文件文件夾(空)除了新的重新編號與用戶信息我不知道這是什麼手段。也許你可以詳細說明。

我是否正確銷燬會話? 不是。在刪除服務器端cookie之前,您還需要嘗試強制客戶端刪除其會話cookie。這是here

作爲最後一點,我不確定檢查客戶端的USER_AGENT是一個好主意,尤其是因爲它很容易被欺騙。您應該考慮檢查完整(不是散列)的IP地址,因爲它需要3次握手。 (請注意,除非您通過SSL進行通信,否則這仍然容易受到MITM攻擊)

+0

沒有session_regenerate_id():用戶可以提交他自己的會話。在其他問題上陷入困境。我選擇了用戶代理而不是IP,因爲IP可以更改。 – domino

+0

「我注意到,如果我修改會話cookie之前登錄相同的會話文件獲取保存在會話文件文件夾(空)除了新的重新編號與用戶信息」 - 我的意思是,如果我編輯PHPSESSION cookie然後登錄,會話文件與用戶提交的名字保存在會話文件夾中。這是空的。 – domino

+0

即使您重新生成,用戶也將始終能夠提交自己的會話。再生只是給他們一個新的會話ID - 如果他們真的是惡意的,他們會忽略它,並繼續與任意會話ID聯繫。確保會話ID匹配客戶端的某個唯一標識符是您的工作。我認爲IP地址比用戶代理更好,但IP地址將受到MITM攻擊,除非您通過SSL。 – jedwards