Sécurité de session PHP

125

Quelles sont les directives pour maintenir une sécurité de session responsable avec PHP? Il y a des informations partout sur le Web et il est temps que tout atterrisse au même endroit!

saint_groceon
la source

Réponses:

88

Il y a plusieurs choses à faire pour sécuriser votre session:

  1. Utilisez SSL lors de l'authentification des utilisateurs ou de l'exécution d'opérations sensibles.
  2. Régénérez l'ID de session chaque fois que le niveau de sécurité change (comme la connexion). Vous pouvez même régénérer l'identifiant de session à chaque demande si vous le souhaitez.
  3. Les sessions expirent
  4. N'utilisez pas de registre global
  5. Stockez les détails d'authentification sur le serveur. Autrement dit, n'envoyez pas de détails tels que le nom d'utilisateur dans le cookie.
  6. Vérifiez le $_SERVER['HTTP_USER_AGENT']. Cela ajoute un petit obstacle au détournement de session. Vous pouvez également vérifier l'adresse IP. Mais cela pose des problèmes pour les utilisateurs dont l'adresse IP change en raison de l'équilibrage de charge sur plusieurs connexions Internet, etc. (ce qui est le cas dans notre environnement ici).
  7. Verrouillez l'accès aux sessions sur le système de fichiers ou utilisez la gestion de session personnalisée
  8. Pour les opérations sensibles, envisagez de demander aux utilisateurs connectés de fournir à nouveau leurs informations d'authentification
grom
la source
15
L'utilisation de SSL uniquement pour certaines opérations n'est pas suffisante, sauf si vous avez des sessions séparées pour le trafic chiffré et non chiffré. Si vous utilisez une seule session sur HTTPS et HTTP, l'attaquant la volera lors de la première requête non HTTPS.
Kornel
6
-1 l'agent utilisateur est facile à usurper. Ce que vous décrivez gaspille du code et n'est pas un système de sécurité.
tour
24
@The Rook, cela peut être une barrière insignifiante (l'attaquant peut capturer l'agent utilisateur d'une victime en utilisant son propre site) et s'appuie sur la sécurité par l'obscurité, mais c'est toujours une barrière supplémentaire. Si le HTTP User-Agent devait changer pendant l'utilisation de la session, ce serait extrêmement suspect et très probablement une attaque. Je n'ai jamais dit que vous pouviez l'utiliser seul. Si vous le combinez avec les autres techniques, vous avez un site beaucoup plus sécurisé.
grom
5
@grom Je pense que c'est comme mettre un morceau de scotch en travers de votre porte et dire que cela empêchera les gens d'entrer par effraction.
Tour
8
Si vous vérifiez l'agent utilisateur, vous bloquerez toutes les demandes des utilisateurs IE8 lorsqu'ils basculeront en mode de compatibilité. Voyez le plaisir que j'ai eu à traquer ce problème dans mon propre code: serverfault.com/questions/200018/http-302-problem-on-ie7 . Je prends le contrôle de l'agent utilisateur, car c'est une chose tellement triviale à usurper, comme d'autres l'ont dit.
meilleure participation
15

Une règle consiste à appeler session_regenerate_id chaque fois que le niveau de sécurité d'une session change. Cela permet d'éviter le détournement de session.

saint_groceon
la source
11

Mes deux (ou plus) centimes:

  • Ne fais confiance a personne
  • Entrée de filtre, sortie d'échappement (cookie, données de session sont également votre entrée)
  • Évitez XSS (gardez votre HTML bien formé, jetez un œil à PHPTAL ou HTMLPurifier )
  • Défense en profondeur
  • Ne pas exposer les données

Il y a un petit mais bon livre sur ce sujet: Essential PHP Security par Chris Shiflett .

Sécurité PHP essentielle http://shiflett.org/images/essential-php-security-small.png

Sur la page d'accueil du livre, vous trouverez des exemples de code intéressants et des exemples de chapitres.

Vous pouvez utiliser la technique mentionnée ci-dessus (IP et UserAgent), décrite ici: Comment éviter le vol d'identité

prend
la source
+1 pour la prévention XSS. Sans cela, il est impossible de se protéger contre le CSRF, et donc quelqu'un peut "monter" la session sans même obtenir l'identifiant de session.
Kornel
11

Je pense que l'un des problèmes majeurs (qui est abordé dans PHP 6) est register_globals. À l'heure actuelle, l'une des méthodes standard utilisées pour éviter register_globalsconsiste à utiliser les tableaux $_REQUEST, $_GETou $_POST.

La manière "correcte" de le faire (à partir de la version 5.2, bien que ce soit un peu bogué là-bas, mais stable à partir de 6, qui arrive bientôt) est à travers des filtres .

Donc au lieu de:

$username = $_POST["username"];

vous feriez:

$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

ou même simplement:

$username = filter_input(INPUT_POST, 'username');
cmcculloh
la source
2
Cela n'a aucun rapport avec la question.
The Pixel Developer
5
Vraiment? Alors pourquoi dans la réponse acceptée mentionnent-ils de ne pas utiliser les registres globaux? En ce qui concerne la plupart des développeurs ordinaires, les globaux de registre et la gestion des variables de formulaire ne tomberaient-ils pas sous l'égide de "sessions" même si cela ne fait pas techniquement partie de l'objet "session"?
cmcculloh
9
Je suis d'accord, cela ne répond pas entièrement à la question, mais cela fait certainement partie de la réponse à la question. Encore une fois, cela étoffe un point dans la réponse acceptée, "Ne pas utiliser les globaux de registre". Cela dit quoi faire à la place.
cmcculloh
5

L'utilisation d'une adresse IP n'est pas vraiment la meilleure idée de mon expérience. Par exemple; mon bureau a deux adresses IP qui sont utilisées en fonction de la charge et nous rencontrons constamment des problèmes avec les adresses IP.

Au lieu de cela, j'ai opté pour le stockage des sessions dans une base de données distincte pour les domaines sur mes serveurs. De cette façon, personne sur le système de fichiers n'a accès à ces informations de session. Cela a été vraiment utile avec phpBB avant la version 3.0 (ils ont depuis corrigé ce problème) mais c'est toujours une bonne idée, je pense.

Eric Lamb
la source
3

C'est assez trivial et évident, mais assurez-vous de session_destroy après chaque utilisation. Cela peut être difficile à mettre en œuvre si l'utilisateur ne se déconnecte pas explicitement, de sorte qu'une minuterie peut être définie pour ce faire.

Voici un bon tutoriel sur setTimer () et clearTimer ().

bonjourandre
la source
3

Le principal problème avec les sessions PHP et la sécurité (outre le piratage de session) vient de l'environnement dans lequel vous vous trouvez. Par défaut, PHP stocke les données de session dans un fichier dans le répertoire temporaire du système d'exploitation. Sans aucune réflexion ou planification particulière, il s'agit d'un répertoire lisible dans le monde entier, de sorte que toutes les informations de votre session sont publiques à toute personne ayant accès au serveur.

Quant au maintien des sessions sur plusieurs serveurs. À ce stade, il serait préférable de basculer PHP vers des sessions gérées par l'utilisateur où il appelle vos fonctions fournies à CRUD (créer, lire, mettre à jour, supprimer) les données de session. À ce stade, vous pouvez stocker les informations de session dans une base de données ou une solution de type Memcache afin que tous les serveurs d'applications aient accès aux données.

Le stockage de vos propres sessions peut également être avantageux si vous êtes sur un serveur partagé car il vous permettra de le stocker dans la base de données sur laquelle vous avez souvent plus de contrôle que le système de fichiers.

John Downey
la source
3

J'ai organisé mes sessions comme ça-

sur la page de connexion:

$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);

(phrase définie sur une page de configuration)

puis sur l'en-tête qui se trouve dans le reste du site:

session_start();
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) {       
    session_destroy();
    header('Location: http://website login page/');
    exit();     
}
Tchad
la source
3

php.ini

session.cookie_httponly = 1
change session name from default PHPSESSID

eq Apache add en-tête:

X-XSS-Protection    1
user956584
la source
httpd.conf -> <FilesMatch "\. (php | phtml | aspx | htm | html) $"> Ensemble d'en-têtes X-XSS-Protection "1" </FilesMatch>
user956584
Sachez que ce X-XSS-Protectionn'est pas du tout utile. En fait, l'algorithme de protection lui-même pourrait en fait être exploité, ce qui le rend pire qu'avant.
Pacerier
2

Je vérifierais à la fois l'IP et l'agent utilisateur pour voir s'ils changent

if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
    || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
    //Something fishy is going on here?
}
Teifion
la source
5
L'IP peut légitimement changer si l'utilisateur se trouve derrière une batterie de serveurs proxy à charge équilibrée.
Kornel
2
Et user_agent peut changer chaque fois qu'un utilisateur met à niveau son navigateur.
scotts
3
@scotts Je suis d'accord avec la partie IP, mais pour la mise à niveau du navigateur, vous définiriez la session lorsqu'ils se connectent afin que je ne vois pas comment ils mettront à niveau leur navigateur sans créer une nouvelle session une fois qu'ils se reconnecteront.
JasonDavis
Je crois que user_agent peut également changer lors du basculement entre le mode compatible dans IE8. Il est également très facile de truquer.
Oui, mais qu'en est-il des utilisateurs qui avaient un eq GSM statique et qui est changé toutes les demi-heures. Donc, IP stockée dans Session + nom d'hôte, WHEN IP! = REMOTE_ADDR vérifier l'hôte et comparer hostanmes eq. 12.12.12.holand.nl-> quand holand.nl == true. Mais certains hôtes avaient un nom d'hôte basé sur IP, alors besoin de comparer le masque 88.99.XX.XX
user956584
2

Si vous utilisez session_set_save_handler (), vous pouvez définir votre propre gestionnaire de session. Par exemple, vous pouvez stocker vos sessions dans la base de données. Reportez-vous aux commentaires de php.net pour des exemples de gestionnaire de session de base de données.

Les sessions de base de données sont également utiles si vous avez plusieurs serveurs, sinon si vous utilisez des sessions basées sur des fichiers, vous devez vous assurer que chaque serveur Web a accès au même système de fichiers pour lire / écrire les sessions.

ejunker
la source
2

Vous devez vous assurer que les données de session sont en sécurité. En regardant votre php.ini ou en utilisant phpinfo (), vous pouvez trouver vos paramètres de session. _session.save_path_ vous indique où ils sont enregistrés.

Vérifiez l'autorisation du dossier et de ses parents. Il ne doit pas être public (/ tmp) ou accessible par d'autres sites Web sur votre serveur partagé.

En supposant que vous souhaitiez toujours utiliser la session php, vous pouvez configurer php pour utiliser un autre dossier en modifiant _session.save_path_ ou enregistrer les données dans la base de données en modifiant _session.save_handler_.

Vous pourriez être en mesure de mettre _session.save_path_ dans votre php.ini (certains fournisseurs permettent) ou apache + mod_php, dans un fichier .htaccess dans votre dossier racine du site: php_value session.save_path "/home/example.com/html/session". Vous pouvez également le définir au moment de l'exécution avec _session_save_path () _.

Vérifiez le tutoriel de Chris Shiflett ou Zend_Session_SaveHandler_DbTable pour définir un gestionnaire de session alternatif.

Dinoboff
la source