Par Valentin Brosseau / @c4software
Jusqu'ici, vos TP tournaient sur localhost.
Bientôt : un stage, un projet, un site en ligne.
Et là, tout le monde peut taper dedans.
Qui voudrait attaquer un petit site de BTS ?
Personne ne me connaît, je n'ai rien à voler.
La sécurité ne commence pas quand le site devient célèbre.
Ce qui peut vous vouloir du mal.
La menace existe, que votre code soit bon ou non.
La faiblesse, chez vous, dans votre code.
$id = $_GET['id'];
$pdo->query("SELECT * FROM livres WHERE id = $id");Un $_GET concaténé dans une requête : voilà une vulnérabilité.
Le risque, c'est la rencontre des deux :
probabilité qu'une menace exploite une vulnérabilité × impact
Pas de vulnérabilité, pas de risque. Pas d'impact non plus.
menace + vulnérabilité = risque
(dehors) (chez vous) (à mesurer)Vous ne pouvez rien contre la menace.
Vous pouvez tout contre la vulnérabilité.
Quel est le risque si votre générateur de punitions est piraté ?
Et si c'est la base des adhérents de la médiathèque ?
Les données personnelles sont protégées par le RGPD : une fuite doit être déclarée, et elle engage la responsabilité de l'organisation.
Tout ce qui arrive dans votre script vient de l'extérieur :
$_GET, $_POST,index.php?page=homeQui écrit la valeur de page ?
$whitelist = ['home', 'bart', 'contact'];
$page = $_GET['page'] ?? 'home';
if (!in_array($page, $whitelist)) {
$page = 'home';
}Vous le faites déjà depuis le TP 3 : c'est de la sécurité.
Même logique ailleurs : isset, filter_var, in_array.
Dans votre livre d'or, quelqu'un laisse cette idée :
<script>alert(1)</script>Vous la réaffichez telle quelle. Que fait le navigateur ?
Le navigateur ne distingue pas votre HTML de celui du visiteur : c'est une faille XSS (Cross-Site Scripting).
echo htmlspecialchars($idee, ENT_QUOTES, 'UTF-8');<script> devient <script> : affiché comme du texte, jamais exécuté.
Valider à l'entrée, échapper à la sortie : les deux, toujours.
$sql = "SELECT * FROM utilisateurs
WHERE login = '$login' AND mot_de_passe = '$mdp'";Ça marche très bien. C'est bien le problème.
Et si je saisis comme login :
' OR 1=1 --Que devient la requête ?
SELECT * FROM utilisateurs
WHERE login = '' OR 1=1 -- ' AND mot_de_passe = '...'1=1 est vrai, le reste est en commentaire.
Connecté en admin, sans mot de passe.
$stmt = $pdo->prepare(
"SELECT * FROM utilisateurs WHERE login = ? AND mot_de_passe = ?"
);
$stmt->execute([$login, $mdp]);La valeur arrive après l'analyse du SQL : elle ne peut plus devenir du code.
| id | login | mot_de_passe |
| 1 | admin | motdepasseadmin |Une fuite de la base, et tous les comptes sont ouverts.
Souvent bien au-delà : les gens réutilisent leurs mots de passe.
// Inscription
$hash = password_hash($mdp, PASSWORD_DEFAULT);
// Connexion
password_verify($saisi, $hash); // true / falseUne fonction à sens unique : on ne revient jamais en arrière.
password_hash fait les deux pour vous. On le voit au TP authentification.
session_regenerate_id(true); // juste après la connexion
session_destroy(); // à la déconnexionEt en production : display_errors = Off.
Un message d'erreur PHP affiché, c'est un plan de votre application offert à l'attaquant.
password_hash et password_verify.Menace + vulnérabilité = risque. Vous travaillez sur la vulnérabilité.
Place à la pratique 🚀