2010-03-29 84 views
12

我剛剛有一個網站來管理,但我不太清楚前面的人寫的代碼。我正在粘貼下面的登錄程序,您能否看看並告訴我是否有任何安全漏洞?乍一看,似乎可以通過SQL注入或操作cookie和?m =參數進入。這個PHP代碼中是否有安全漏洞?


 

define ('CURRENT_TIME', time());// Current time. 
define ('ONLINE_TIME_MIN', (CURRENT_TIME - BOTNET_TIMEOUT));// Minimum time for the status of "Online". 
define ('DEFAULT_LANGUAGE', 'en');// Default language. 
define ('THEME_PATH', 'theme');// folder for the theme. 

// HTTP requests. 
define ('QUERY_SCRIPT', basename ($ _SERVER [ 'PHP_SELF'])); 
define ('QUERY_SCRIPT_HTML', QUERY_SCRIPT); 
define ('QUERY_VAR_MODULE', 'm');// variable contains the current module. 
define ('QUERY_STRING_BLANK', QUERY_SCRIPT. '? m =');// An empty query string. 
define ('QUERY_STRING_BLANK_HTML', QUERY_SCRIPT_HTML. '? m =');// Empty query string in HTML. 
define ('CP_HTTP_ROOT', str_replace ('\ \', '/', (! empty ($ _SERVER [ 'SCRIPT_NAME'])? dirname ($ _SERVER [ 'SCRIPT_NAME']):'/')));// root of CP. 

// The session cookie. 
define ('COOKIE_USER', 'p');// Username in the cookies. 
define ('COOKIE_PASS', 'u');// user password in the cookies. 
define ('COOKIE_LIVETIME', CURRENT_TIME + 2592000)// Lifetime cookies. 
define ('COOKIE_SESSION', 'ref');// variable to store the session. 
define ('SESSION_LIVETIME', CURRENT_TIME + 1300)// Lifetime of the session. 

////////////////////////////////////////////////// ///////////////////////////// 
// Initialize. 
////////////////////////////////////////////////// ///////////////////////////// 

// Connect to the database. 
if (! ConnectToDB()) die (mysql_error_ex()); 

// Connecting topic. 
require_once (THEME_PATH. '/ index.php'); 

// Manage login. 
if (! empty ($ _GET [QUERY_VAR_MODULE])) 
( 
// Login form. 
    if (strcmp ($ _GET [QUERY_VAR_MODULE], 'login') === 0) 
    ( 
    UnlockSessionAndDestroyAllCokies(); 

    if (isset ($ _POST [ 'user']) & & isset ($ _POST [ 'pass'])) 
    ( 
     $ user = $ _POST [ 'user']; 
     $ pass = md5 ($ _POST [ 'pass']); 

    // Check login. 
     if (@ mysql_query ("SELECT id FROM cp_users WHERE name = '". addslashes ($ user). "' AND pass = '". addslashes ($ pass). "' AND flag_enabled = '1 'LIMIT 1") & & @ mysql_affected_rows() == 1) 
     ( 
     if (isset ($ _POST [ 'remember']) & & $ _POST [ 'remember'] == 1) 
     ( 
      setcookie (COOKIE_USER, md5 ($ user), COOKIE_LIVETIME, CP_HTTP_ROOT); 
      setcookie (COOKIE_PASS, $ pass, COOKIE_LIVETIME, CP_HTTP_ROOT); 
     ) 

     LockSession(); 
     $ _SESSION [ 'Name'] = $ user; 
     $ _SESSION [ 'Pass'] = $ pass; 
     // UnlockSession(); 

     header ('Location:'. QUERY_STRING_BLANK. 'home'); 
    ) 
     else ShowLoginForm (true); 
     die(); 
    ) 

    ShowLoginForm (false); 
    die(); 
) 

// Output 
    if (strcmp ($ _GET [ 'm'], 'logout') === 0) 
    ( 
    UnlockSessionAndDestroyAllCokies(); 
    header ('Location:'. QUERY_STRING_BLANK. 'login'); 
    die(); 
) 
) 

////////////////////////////////////////////////// ///////////////////////////// 
// Check the login data. 
////////////////////////////////////////////////// ///////////////////////////// 

$ logined = 0,// flag means, we zalogininy. 

// Log in session. 
LockSession(); 
if (! empty ($ _SESSION [ 'name']) & &! empty ($ _SESSION [ 'pass'])) 
( 
    if (($ r = @ mysql_query ("SELECT * FROM cp_users WHERE name = '". addslashes ($ _SESSION [' name'])."' AND pass = ' ". addslashes ($ _SESSION [' pass']). " 'AND flag_enabled = '1' LIMIT 1 ")))$ logined = @ mysql_affected_rows(); 
) 
// Login through cookies. 
if ($ logined! == 1 & &! empty ($ _COOKIE [COOKIE_USER]) & &! empty ($ _COOKIE [COOKIE_PASS])) 
( 
    if (($ r = @ mysql_query ("SELECT * FROM cp_users WHERE MD5 (name)='". addslashes ($ _COOKIE [COOKIE_USER ])."' AND pass = '". addslashes ($ _COOKIE [COOKIE_PASS]). " 'AND flag_enabled = '1' LIMIT 1 ")))$ logined = @ mysql_affected_rows(); 
) 
// Unable to login. 
if ($ logined! == 1) 
( 
    UnlockSessionAndDestroyAllCokies(); 
    header ('Location:'. QUERY_STRING_BLANK. 'login'); 
    die(); 
) 

// Get the user data. 
$ _USER_DATA = @ Mysql_fetch_assoc ($ r); 
if ($ _USER_DATA === false) die (mysql_error_ex()); 
$ _SESSION [ 'Name'] = $ _USER_DATA [ 'name']; 
$ _SESSION [ 'Pass'] = $ _USER_DATA [ 'pass']; 

// Connecting language. 
if (@ strlen ($ _USER_DATA [ 'language'])! = 2 | |! SafePath ($ _USER_DATA [ 'language']) | |! file_exists ('system/lng .'.$_ USER_DATA [' language '].' . php'))$_ USER_DATA [ 'language'] = DEFAULT_LANGUAGE; 
require_once ('system/lng .'.$_ USER_DATA [' language'].'. php '); 

UnlockSession(); 
+4

包括本網站的地址,我會讓你知道的。 :) – MusiGenesis 2010-03-29 21:14:48

+0

使用addslashes(md5($ pass))是多餘的。 SQL注入不能讓它想到md5(),它可以*有時*使它傳遞addslashes()。另外,md5()永遠不會生成單引號,double-qutoes,反斜線或空字節,因此addslashes()將永遠不會對md5()哈希執行任何操作。它更好地使用adodb和參數化查詢。 – rook 2010-03-29 21:23:04

回答

17

是的,有這個代碼的一些漏洞。

這可能是一個問題:

define ('QUERY_SCRIPT', basename ($ _SERVER [ 'PHP_SELF'])); 

PHP_SELF是不好的,因爲攻擊者可以控制這個變量。例如,當您使用此URL訪問腳本時,請嘗試打印PHP_SELFhttp://localhost/index.php/test/junk/hacked。儘可能避免使用此變量,如果您確實使用它,請確保清除它。當使用這個變量時,看到XSS突然出現是很常見的。

1日漏洞:

setcookie (COOKIE_USER, md5 ($ user), COOKIE_LIVETIME, CP_HTTP_ROOT); 
setcookie (COOKIE_PASS, $ pass, COOKIE_LIVETIME, CP_HTTP_ROOT); 

這是一個相當嚴重的漏洞。如果攻擊者在您的應用程序中有SQL注入,那麼他們可以立即獲取md5散列和用戶名並立即登錄,而不必中斷md5()散列。就好像您以明文形式存儲密碼。

此會話漏洞是兩方面的,它也是一個「永久會話」,會話ID必須始終是隨機生成的大量過期值。如果他們沒有到期,那麼他們更容易暴力。

您應該從不重新發明車輪,在您的應用程序的一開始就打電話session_start(),這將自動生成一個安全的會話ID過期。然後使用一個會話變量像$_SESSION['user']跟蹤如果瀏覽器在實際登錄

第二個漏洞:

$ pass = md5 ($ _POST [ 'pass']); 

md5()被證明是不安全的,因爲衝突被有意產生。 md5()應該使用從不使用用於密碼。你應該使用sha2家族的成員,sha-256或sha-512是很好的選擇。

第三漏洞:

CSRF

我沒有看到你的身份驗證邏輯的任何CSRF保護。我懷疑您的應用程序中的所有請求都容易受到CSRF的影響。

+1

OMG基於謠言而不是知識的答案。 – 2010-03-31 06:12:20

+2

謹慎地用特定的上校量化你的觀點? – Neil 2010-03-31 10:39:09

+4

@Col。彈片真的嗎?我所看到的只是經過多年研究的支持。 – rook 2010-03-31 17:38:15

0

接受的答案缺少很多,錯了幾件事情。以下是我在代碼中看到的漏洞:

define('QUERY_SCRIPT', basename($_SERVER['PHP_SELF'])); 

如其他地方所述,這可以包含多個腳本路徑。改爲使用$_SERVER['SCRIPT_NAME']__FILE__

define('CP_HTTP_ROOT', ... 

此常量用於設置腳本路徑的cookie路徑。這並非不安全,但用戶需要分別登錄每個腳本。而是使用會話(下面討論)併爲您的應用程序設置一個基本路徑。

UnlockSessionAndDestroyAllCokies() 

我不知道這是幹什麼,但聽起來不太好。 只需在每個請求的腳本中儘早啓動會話即可。檢查會話中的現有用戶信息,知道他們是否已經登錄。

$pass = md5($_POST['pass']); 

密碼應具有與每個哈希獨特的鹽,最好使用一個更好的散列算法。 這些天(PHP 5.5+)你應該使用password_hashpassword_verify來照顧你的密碼哈希細節。

mysql_query("SELECT id FROM cp_users WHERE name = '". addslashes($user)... 

這是一個老問題,但今天mysql_ PHP功能不再支持。使用mysqli或PDO。 使用不受支持的庫會讓您打開未修補的漏洞addslashes不是針對SQL注入的完美保護。 使用準備好的語句,或者至少是庫的字符串轉義函數。

if (isset($_POST['remember']) && $_POST['remember'] == 1) 
( 
    setcookie(COOKIE_USER, md5($user), COOKIE_LIVETIME, CP_HTTP_ROOT); 
    setcookie(COOKIE_PASS, $pass, COOKIE_LIVETIME, CP_HTTP_ROOT); 
) 

這裏是最大的問題。 Cookie正在存儲用戶憑證。您正在發回已散列的用戶名,並將密碼散列爲響應中的Cookie值。這些可以很容易地被第三方閱讀和使用。由於該腳本使用簡單的哈希表,因此彩虹表可以讓別人查看許多用戶密碼。但是由於響應包含「安全」證書,因此攻擊者除了將其傳遞給任何其他登錄請求外,無需執行任何操作。這不是「記住」用戶的正確方法,也不是必需的。

用戶與請求的連接應僅在會話中處理。這是他們的目的。請求和響應包含一個帶有隨機標識符的cookie。 用戶詳細信息僅保留在服務器上並鏈接到此標識符。 (附註:有這個塊包裹着括號,而不是大括號中的錯誤)

$_SESSION['Pass'] = $pass; 

現在用戶的密碼被存儲在兩個地方:數據庫和會話存儲。如果會話存儲在數據庫之外(並且PHP默認將它們存儲在磁盤上),那麼現在有兩種方法可以嘗試竊取用戶憑據。

if ($logined !== 1 && !empty($_COOKIE[COOKIE_USER]) ... 
    if (($r = @mysql_query("SELECT * FROM cp_users WHERE MD5(name)='". addslashes($_COOKIE [COOKIE_USER ])."' AND pass = '". addslashes($_COOKIE [COOKIE_PASS]).. 

攻擊者現在可以嘗試通過簡單地通過cookie頭與一個用戶名和密碼,這是交給他們先前響應的MD5哈希的請求登錄。登錄表單應該是唯一獲取用戶憑據並登錄的地方。此表單(以及所有其他表單)應使用CSRF標記。

UnlockSession(); 

我再次不知道這是做什麼,但在腳本結束時,會話應該寫入存儲。