这个PHP代码中是否有安全漏洞?
我刚刚有一个网站来管理,但我不太确定前面的人写的代码。 我正在粘贴下面的登录程序,您能否看看并告诉我是否有任何安全漏洞? 乍一看,似乎可以通过SQL注入或操作cookie和?m =参数进入。
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 ();
是的,这个代码中有一些漏洞。
这可能是一个问题:
define ( 'QUERY_SCRIPT', basename ($ _SERVER [ 'PHP_SELF']));
PHP_SELF
不好,因为攻击者可以控制这个变量。 例如,当你用这个URL访问脚本时试试打印PHP_SELF
: http://localhost/index.php/test/junk/hacked
。 尽可能避免使用此变量,如果您确实使用它,请确保清除它。 当使用这个变量时,看到XSS突然出现是很常见的。
1st漏洞:
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()
,这会自动生成一个过期的安全会话标识。 然后使用会话变量(如$_SESSION['user']
来跟踪浏览器是否实际登录。
第二个漏洞:
$ pass = md5 ($ _POST [ 'pass']);
md5()
被证明是不安全的,因为碰撞是有意产生的。 md5() 不应该用于密码。 你应该使用sha2家族的成员,sha-256或sha-512是很好的选择。
第三个漏洞:
CSRF
我没有看到任何CSRF保护您的身份验证逻辑。 我怀疑您的应用程序中的所有请求都容易受到CSRF的影响。
接受的答案在一些事情上缺少很多错误。 以下是我在代码中看到的漏洞:
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_hash
和password_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散列中传递cookie,并在之前的响应中传递给它们。 登录表单应该是唯一获取用户凭据并登录的地方。此表单(以及所有其他表单)应使用CSRF标记。
UnlockSession();
我再次不知道这是怎么回事,但是在脚本结束时,会话只能写入存储。
链接地址: http://www.djcxy.com/p/21879.html上一篇: Are there any security vulnerabilities in this PHP code?
下一篇: How do I make a request using HTTP basic authentication with PHP curl?