TP de sécurité en PHP

Le TP se déroulera autour d'une application factice : un mini-blog. Les fonctionnalités sont volontairement limitées, et le code PHP très simplifié, mais les failles de sécurité sont les mêmes que dans des applications réelles.

Formulaires et HTML

Modification de contenu

  1. Placer l'application dans un répertoire de son serveur web. Consulter les articles existant, et les différentes pages. Se créer un compte utilisateur et s'authentifier.
  2. Une fois authentifié, poster un commentaire sur un article.
    Modifier son commentaire.
    Modifier le commentaire d'un autre utilisateur !
  3. Sécuriser l'écriture du formulaire de la page "comment_create.php" afin qu'on ne puisse pas accéder à un commentaire d'autrui.
  4. Est-ce suffisant ? Comment modifier malgré tout ce formulaire ?
  5. Plutôt que de mettre en place la même sécurité dans le traitement du formulaire que dans son écriture, on souhaite vérifier que certains champs du formulaire soumis sont bien identiques à celles attendues. Ajouter au formulaire un champ qui permette ceci.

XSS

  1. Ajouter un commentaire qui masque le bas de page (tout ce qui suit son commentaire est masqué).
    Revenir à un fonctionnement normal.
  2. Ajouter un commentaire qui modifie le titre H1 de la page de l'article.
  3. Empêcher la saisie de balises HTML (en les supprimant) pour éviter les attaques ci-dessus. Est-ce suffisant ?
  4. Echapper (protéger) les textes affichés dans le HTML. Est-ce satisfaisant ?
  5. Utiliser la bibliothèque PHP HTML Purifier pour autoriser l'utilisateur à mettre du HTML dans ses commentaires, mais en court-circuitant les attaques.
  6. On considère que les champs des commentaires sont maintenant sécurisés. Fixer l'URL d'un compte utilisateur de façon à exploiter une faille XSS sur la page "article_view.php". Comment corriger cette faille ? Quelle est la particularité par rapport aux points précédents ?
  7. Proposer une URL vers la page "user_login.php" qui affiche dans une popup les login/mot de passe saisis. Sur le même principe, on peut envoyer ces informations à un site collecteur. Cliquer sur un lien est dangereux !
    On veut insérer dans le HTML de la page, dans le champ "login" :
    "><script>f=document.forms[0];f.onsubmit='alert(f.elements[2].value)';</script><span class="aa
    Ce qui donne l'URL relative : user_login.php?login=%22/%3E%3Cscript%3Ef=document.forms[0];f.onsubmit='alert(f.elements[2].value)';%3C/script%3E%3Cspan%20class=%22aaa

CSRF

  1. Se rendre sur la page "csrf.html". Que c'est-il passé ?
  2. Comment empêcher simplement cette attaque ?
    Si la page PHP lit du POST, le danger est plus faible puisque qu'une action à l'insu de son auteur ne peut se faire que via du Javascript.
  3. Télécharger jQuery. Utiliser $.post() pour créer une attaque CSS similaire à la précédente.
  4. Mettre en place un CAPTCHA avec Securimage.
  5. Supprimer le CAPTCHA. Utiliser des valeurs secrètes en session pour sécuriser la requête.

Pour aller plus loin

  1. Installer "Savant3" à l'aide de "pear". Récrire la page "comment_create.php" pour utiliser un template.
  2. Remplacer le formulaire HTML de "comment_create.php" par un formulaire QuickForm. En complément de la documentation officielle, on pourra se référer à un tutoriel QuickForm.

Injection SQL

Échappement SQL

  1. Sur la page "user_login.php", se connecter sans mot de passe, juste avec un login valide.
  2. Se connecter sans mot de passe ni login.
  3. Quel rôle joue ici la fonction noMagicQuotes() ? La directive "magic_quotes_gpc", par défaut à ON avant PHP 4.3, est maintenant à OFF en général. Pourquoi cette fonctionnalité est-elle devenue obsolète en PHP ?
  4. Sécuriser la page avec PDO::quote(), l'équivalent de mysqli::real_escape_string().

L'échappement ne suffit pas

  1. Sur la page "comment_create.php", malgré l'échappement SQL, prouver que l'on peut toujours modifier des commentaires d'autrui. Par exemple, effacer tous les commentaires qui suivent l'un des siens.
  2. La protection en sortie (échappement SQL) ne suffit pas. Il faut prévoir une protection en entrée : la validation des données entrantes. C'est non seulement utile pour la sécurité, mais aussi pour la cohérence de l'application. Appliquer ce principe à "comment_create.php".
  3. Utiliser ext/filter pour valider tous les paramètres POST en une fois.
  4. Sécuriser la page avec des requêtes préparées. Vérifier si l'attaque ci-dessus est encore possible, même sans phase de validation.

Sessions

  1. Utiliser une faille XSS pour afficher le contenu du cookie (en javascript : document.cookie). Voler alors la session associée (tester dans un autre navigateur).
  2. Rendre l'attaque précédente plus réaliste : sur la page "article_view.php", le cookie du visiteur devra être envoyé à une URL où un script PHP l'écrira dans un fichier (utiliser error_log()).
  3. Créer une page HTML avec un lien vers la page de login qui fixe l'ID de session. Supprimer tous les cookies, puis suivre ce lien. Vérifier alors dans un autre navigateur que l'ID de session choisi est valide.
  4. Appliquer les sécurisations recommandées (configuration et régénération d'ID). Tester à nouveau les attaques précédentes.

Le TP est fini. Se référer aux transparents pour les détails et les aspects théoriques.