2010-03-29 79 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(); 

我再次不知道这是做什么,但在脚本结束时,会话应该写入存储。