2010-03-29 14 views
12

J'ai juste un site à gérer, mais je ne suis pas trop sûr du code que le gars précédent a écrit. Je colle la procédure de connexion ci-dessous, pourriez-vous jeter un coup d'oeil et me dire s'il y a des failles de sécurité? À première vue, il semble que l'on pourrait entrer dans l'injection SQL ou manipuler les cookies et le paramètre? M =.Y a-t-il des failles de sécurité dans ce code 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

Incluez l'adresse de ce site, et je vous le ferai savoir. :) – MusiGenesis

+0

L'utilisation de addslashes (md5 ($ pass)) est redondante. SQL Injection ne peut pas faire penser à md5(), il peut * parfois * le faire passer addslashes(). De plus, md5() ne générera jamais de guillemets simples, de doubles-qutoes, de backslashes ou d'octets nuls, donc addslashes() ne fera jamais rien à un hachage md5(). Il est préférable d'utiliser des requêtes adodb et paramétrées. – rook

Répondre

17

Oui, il y a quelques vulnérabilités dans ce code.

Cela pourrait être un problème:

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

PHP_SELF est mauvais, car un attaquant peut contrôler cette variable. Par exemple, essayez d'imprimer PHP_SELF lorsque vous accédez au script avec cette URL: http://localhost/index.php/test/junk/hacked. Evitez autant que possible cette variable, si vous l'utilisez, assurez-vous de la désinfecter. Il est très fréquent de voir apparaître XSS lors de l'utilisation de cette variable.

1er Vulnérabilité:

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

Ceci est une vulnérabilité assez grave. Si un attaquant avait une injection SQL dans votre application, il pouvait obtenir le hachage md5 et le nom d'utilisateur et se connecter immédiatement sans avoir à casser le hachage md5(). C'est comme si vous stockez des mots de passe en texte clair.

Cette vulnérabilité de session est double, c'est aussi une "session immortelle", les identifiants de session doivent toujours être de grandes valeurs générées aléatoirement qui expirent. Si elles n'expirent pas, elles sont beaucoup plus faciles à la force brute.

Vous devriez jamais réinventer la roue, appelez session_start() au début de votre application et cela génère automatiquement un identifiant de session sécurisée qui arrive à expiration. Ensuite, utilisez une variable de session comme $_SESSION['user'] de garder une trace si le navigateur est effectivement connecté

2ème vulnérabilité.

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

md5() est prouvé en situation d'insécurité parce que les collisions ont été intentionnellement généré. md5() jamais être utilisé pour les mots de passe. Vous devriez utiliser un membre de la famille sha2, sha-256 ou sha-512 sont d'excellents choix.

3ème vulnérabilité:

CSRF

Je ne vois aucune protection CSRF pour vous la logique d'authentification. Je soupçonne que toutes les demandes dans votre application sont vulnérables à CSRF.

+1

OMG quelle ... réponse basée sur des rumeurs pas une connaissance. –

+2

soin de quantifier votre point avec des détails colonel? – Neil

+4

@Col. Shrapnel Vraiment? Tout ce que je vois est un fait endurci soutenu par des années de recherche. – rook

0

La réponse acceptée est manquant beaucoup et faux sur quelques choses. Voici les vulnérabilités que je vois dans le code:

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

Comme dit ailleurs, cela peut contenir plus que le chemin du script. Utilisez $_SERVER['SCRIPT_NAME'] ou __FILE__ à la place.

define('CP_HTTP_ROOT', ... 

Cette constante est utilisée pour définir le chemin de cookie sur le chemin du script. Ce n'est pas un problème, mais l'utilisateur devra se connecter séparément à chaque script. Utilisez plutôt des sessions (décrites ci-dessous) et définissez un chemin de base pour votre application. Je ne sais pas exactement ce que cela fait, mais ça ne sonne pas bien. Il suffit de démarrer la session au début du script pour chaque demande. Vérifiez les informations d'utilisateur existant dans la session de savoir si elles sont déjà connectés.

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

Les mots de passe doivent avoir un sel unique avec chaque hachage, et utiliser de préférence un meilleur algorithme de hachage. Ces jours-ci (PHP 5.5+), vous devriez utiliser password_hash et password_verify pour prendre soin des détails de hachage de mot de passe pour vous.

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

Ceci est une question ancienne, mais aujourd'hui les mysql_ fonctions PHP ne sont plus pris en charge. Utilisez mysqli ou PDO. L'utilisation d'une bibliothèque non prise en charge vous laisse ouvert aux vulnérabilités non corrigées. addslashes n'est pas une protection parfaite contre l'injection SQL. Utilisez les instructions préparées, ou au moins les fonctions d'échappement de chaîne de la bibliothèque.

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

Et voici le plus gros problème. Les cookies stockent les informations d'identification de l'utilisateur. Vous renvoyez un nom d'utilisateur haché et un mot de passe haché en tant que valeurs de cookie avec la réponse. Ceux-ci peuvent facilement être lus et utilisés par un tiers. Puisque ce script utilise un hash simple, une table arc-en-ciel laissera quelqu'un rechercher beaucoup de mots de passe utilisateur. Mais puisque la réponse contient les informations d'identification "sécurisées", un attaquant n'aurait pas besoin de faire autre chose que de les passer dans une autre requête pour se connecter. Ce n'est pas la bonne façon de "se souvenir" d'un utilisateur et n'est pas nécessaire.

La connexion d'un utilisateur à une demande doit être gérée uniquement dans la session. C'est leur but. Les requêtes et réponses contiennent un cookie avec un identifiant aléatoire. Les détails de l'utilisateur restent uniquement sur le serveur et sont liés à cet identifiant. (Note:. Il y a un bug que ce bloc est enveloppé avec des parenthèses au lieu d'accolades)

$_SESSION['Pass'] = $pass; 

maintenant mot de passe de l'utilisateur est stocké dans deux endroits: la base de données et de stockage session. Si les sessions sont stockées en dehors de la base de données (et PHP les stocke sur le disque par défaut), vous avez maintenant deux façons d'essayer de voler les informations d'identification des utilisateurs.

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]).. 

Un attaquant peut désormais se connecter tenter en en-têtes de cookie en passant simplement dans une requête avec un hachage md5 d'un nom d'utilisateur et mot de passe, qui leur a été remis dans une réponse précédente. Le formulaire de connexion doit être le seul endroit à prendre les informations d'identification de l'utilisateur et à les enregistrer. Ce formulaire (et tous les autres) doit utiliser un jeton CSRF.

UnlockSession(); 

Encore une fois, je ne sais pas ce que cela fait, mais à la fin du script de la session devrait juste être écrit au stockage.