security authentification - Comment fonctionne le détournement de session en PHP?




login exemple (4)

Quelqu'un renifle le cookie d'ID de session et le configure pour une demande ultérieure. Si c'est la seule chose qui a authentifié un utilisateur, ils sont connectés.

La plupart des sites utiliseront une authentification basée sur des cookies sous une forme quelconque. Il existe plusieurs manières de rendre cela plus sûr, comme le stockage d'informations sur le navigateur de l'utilisateur lorsqu'il se connecte (par exemple, agent utilisateur, adresse IP). Si quelqu'un d'autre tente naïvement de copier le cookie, cela ne fonctionnera pas. (Bien sûr, il existe également des moyens de contourner cela.) Vous verrez également des cookies de session régénérés périodiquement pour vous assurer qu'ils ne sont pas valides pendant une période particulièrement longue.

Découvrez Firesheep pour une extension Firefox qui effectue le détournement de session. Je ne vous suggère pas de l'utiliser, mais vous pouvez trouver la discussion intéressante sur cette page.

J'ai créé un site Web avec inscription / connexion. Je peux voir le cookie PHPSESSID dans les outils de développement de Chrome, alors je me demande comment utiliser cette valeur d'ID de session pour pirater le compte que je suis connecté, disons un navigateur différent, par souci de simplicité.

Un site Web sécurisé devrait-il pouvoir déterminer si cette session a été détournée et l’empêcher?

En outre, comment se fait-il que d’autres grands sites utilisant PHP (par exemple, Facebook) n’aient pas de cookies PHPSESSID? Ont-ils un nom différent pour l'obscurité ou utilisent-ils simplement un mécanisme différent?


Beaucoup de bonnes questions et bon pour vous de leur demander.

Tout d'abord, une session n'est qu'un cookie. Une «session» ne fait pas partie de la pile HTTP. PHP arrive juste à fournir quelques commodités qui facilitent le travail avec les cookies, introduisant ainsi des sessions. PHP choisit PHPSESSID comme nom par défaut pour le cookie, mais vous pouvez choisir ce que vous voulez. Même en PHP, vous pouvez changer le nom de la session.

Tout ce qu'un attaquant doit faire est de récupérer le cookie de session que vous consultez et de l'utiliser dans son propre navigateur. L'attaquant peut le faire avec des scripts automatisés ou, par exemple, en utilisant Firebug, vous pouvez simplement modifier les valeurs de cookie actuelles.

Alors oui, si j'ai votre identifiant. Je peux voler votre session si vous n'avez rien fait pour l'empêcher.

Cependant, le plus difficile pour un attaquant est d'obtenir le cookie en premier lieu. L'attaquant ne peut pas vraiment faire cela, à moins que:

  • Ils ont accès à votre ordinateur
  • Ils peuvent en quelque sorte capturer votre trafic réseau.

La première partie est difficile à résoudre. Il y a quelques astuces pour identifier l'ordinateur qui a démarré la session (vérifiez si l'agent utilisateur a changé, vérifiez si l'adresse IP a changé), mais les solutions ne sont pas étanches.

Vous pouvez réparer le second en vous assurant que tout votre trafic est crypté à l'aide de HTTPS. Il y a très peu de raisons de ne pas utiliser HTTPS. Si vous avez une zone "connectée" sur votre site, utilisez SSL!

J'espère que ce genre de réponse répond à votre question. Quelques autres conseils auxquels j'ai pensé tout de suite:

  • Chaque fois qu'un utilisateur se connecte, donnez-lui un nouvel identifiant de session
  • Chaque fois qu'un utilisateur se déconnecte, donnez-lui également un nouvel identifiant de session!
  • Assurez-vous que le navigateur ne peut en aucun cas déterminer la valeur du cookie de session. Si vous ne reconnaissez pas le cookie, régénérez-en un nouveau!

Si vous êtes sur la même adresse IP et que vous utilisez le même navigateur, il vous suffit de dupliquer l'ID de session (et peut-être d'autres valeurs de cookie). dépendant).

En général, il existe différentes manières de suivre les utilisateurs (à la fin, il ne s'agit que du suivi des utilisateurs). Par exemple, vous pouvez utiliser un cookie ou une valeur cachée dans la page Web. Vous pouvez également utiliser une valeur dans les requêtes HTTP GET, un cookie Flash ou une autre méthode d'authentification (ou une combinaison de celles-ci).

Dans le cas de Facebook, ils utilisent plusieurs valeurs de cookies, je suppose donc qu'ils utilisent l'une de ces valeurs (par exemple, «xs»).

Dans l’ensemble, il n’existe pas de véritable moyen sécurisé (par exemple, en raison d’attaques de type intermédiaire), mais dans l’ensemble, je fais ce qui suit:

  • Lors de la connexion, stockez l'adresse IP de l'utilisateur, sa chaîne d'agent de navigateur et un jeton unique (éditez en raison de commentaires ci-dessus: vous pouvez aussi ignorer l'adresse IP, ce qui rend la sécurité un peu moins sécurisée).
  • Le côté client stocke l'identifiant unique de l'utilisateur (par exemple l'ID utilisateur) et ce jeton (dans un cookie ou une valeur GET).
  • Tant que les données stockées dans la première étape correspondent, il s'agit du même utilisateur. Pour vous déconnecter, supprimez simplement le jeton de la base de données.

Oh, et juste pour le mentionner: toutes ces choses ne sont pas spécifiques à PHP. Ils peuvent être réalisés avec n'importe quel langage côté serveur (Perl, PHP, Ruby, C #, ...) ou un serveur en général.


Utilisez des instructions préparées et des requêtes paramétrées. Il s'agit d'instructions SQL qui sont envoyées et analysées par le serveur de base de données indépendamment de tout paramètre. De cette manière, il est impossible à un attaquant d'injecter du code SQL malveillant.

Vous avez essentiellement deux options pour y parvenir:

  1. Utilisation de PDO (pour tout pilote de base de données pris en charge):

    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    
    $stmt->execute(array('name' => $name));
    
    foreach ($stmt as $row) {
        // do something with $row
    }
    
  2. Utilisation de MySQLi (pour MySQL):

    $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
    $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
    
    $stmt->execute();
    
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        // do something with $row
    }
    

Si vous vous connectez à une base de données autre que MySQL, vous pouvez vous référer à une deuxième option spécifique au pilote (par exemple, pg_prepare() et pg_execute() pour PostgreSQL). Le PDO est l'option universelle.

Configurer correctement la connexion

Notez que lorsque vous utilisez PDO pour accéder à une base de données MySQL, les instructions réellement préparées ne sont pas utilisées par défaut . Pour résoudre ce problème, vous devez désactiver l'émulation des instructions préparées. Voici un exemple de création d'une connexion à l'aide de PDO:

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Dans l'exemple ci-dessus, le mode d'erreur n'est pas strictement nécessaire, mais il est conseillé de l'ajouter . De cette façon, le script ne s’arrêtera pas avec une Fatal Error cas de problème. Et cela donne au développeur la possibilité d’ catch toute erreur (s) PDOException (s) en tant que PDOException .

Ce qui est obligatoire , cependant, est la première ligne setAttribute() , qui indique à PDO de désactiver les instructions préparées émulées et d'utiliser de véritables instructions préparées. Cela permet de s’assurer que la déclaration et les valeurs ne sont pas analysées par PHP avant de l’envoyer au serveur MySQL (ce qui permet à un attaquant éventuel d’injecter du code SQL malveillant).

Bien que vous puissiez définir le charset de charset dans les options du constructeur, il est important de noter que les versions "anciennes" de PHP (<5.3.6) ignoraient en silence le paramètre charset du DSN.

Explication

Ce qui se passe, c'est que l'instruction SQL que vous passez à prepare est analysée et compilée par le serveur de base de données. En spécifiant des paramètres (un ? Ou un paramètre nommé tel que :name dans l'exemple ci-dessus), vous indiquez au moteur de base de données sur lequel vous souhaitez filtrer. Ensuite, lorsque vous appelez execute , l'instruction préparée est combinée aux valeurs de paramètre que vous spécifiez.

La chose importante ici est que les valeurs de paramètre sont combinées avec l'instruction compilée, pas une chaîne SQL. L'injection SQL fonctionne en incitant le script à inclure des chaînes malveillantes lorsqu'il crée du code SQL à envoyer à la base de données. Donc, en envoyant le code SQL séparément des paramètres, vous limitez le risque de vous retrouver avec quelque chose que vous ne souhaitiez pas. Tous les paramètres que vous envoyez en utilisant une instruction préparée seront simplement traités comme des chaînes (bien que le moteur de base de données puisse effectuer certaines optimisations, les paramètres peuvent également se transformer en nombres, bien sûr). Dans l'exemple ci-dessus, si la variable $name contient 'Sarah'; DELETE FROM employees 'Sarah'; DELETE FROM employees le résultat serait simplement une recherche de la chaîne "'Sarah'; DELETE FROM employees" et vous ne vous retrouverez pas avec une table vide .

L’utilisation d’instructions préparées présente un autre avantage: si vous exécutez la même instruction plusieurs fois au cours de la même session, elle ne sera analysée et compilée qu’une seule fois, ce qui vous donnera un gain de rapidité.

Oh, et puisque vous avez demandé comment faire pour une insertion, voici un exemple (en utilisant PDO):

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute(array('column' => $unsafeValue));

Des instructions préparées peuvent-elles être utilisées pour des requêtes dynamiques?

Bien que vous puissiez toujours utiliser des instructions préparées pour les paramètres de requête, la structure de la requête dynamique elle-même ne peut pas être paramétrée et certaines fonctionnalités de la requête ne peuvent pas être paramétrées.

Pour ces scénarios spécifiques, la meilleure chose à faire consiste à utiliser un filtre de liste blanche limitant les valeurs possibles.

// Value whitelist
// $dir can only be 'DESC' otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}




php security session cookies