Comprendre pourquoi une API non protégée est un problème, ajouter un token partagé, et discuter de ses limites.
Jusqu'ici, n'importe qui sur le réseau de l'école (ou pire, sur Internet si l'API est exposée) peut :
PC-DU-PROF,C'est inacceptable pour une API en production. Mais on a volontairement attendu cette dernière étape pour que tu vives ce problème avant de le résoudre. C'est comme ça qu'on retient à quoi sert la sécurité.
Sans rien protéger, ouvre Postman et envoie ce JSON :
{
"hostname": "PC-DE-LUDO",
"timestamp": "2026-05-13T08:00:00",
"system": { "os": "Windows 95 LOL" },
"memory": { "totalGo": 0.5 },
"disks": []
}
Recharge le dashboard. Le PC du prof affiche Windows 95 et 512 Mo de RAM. Catastrophe. Tu viens de comprendre pourquoi une API sans authentification n'est pas une API.
Un token est un secret partagé entre :
Le client envoie ce secret dans chaque requête. Le serveur vérifie qu'il correspond avant de traiter quoi que ce soit.
C'est basique mais déjà beaucoup mieux que rien.
💡 Ce n'est pas un mot de passe : un mot de passe identifie une personne, un token identifie une application autorisée. Tu ne demanderais pas à ton script de taper un mot de passe à chaque exécution. Le token, lui, peut vivre dans un fichier de configuration.
Pas dans l'URL :
❌ https://serveur/api/report?token=ABC123
Pourquoi ? Parce que les URLs sont :
Dans un en-tête HTTP :
✅ X-API-Key: ABC123
Les en-têtes ne sont pas affichés dans les logs standards et ne sont pas journalisés par le navigateur.
Crée src/auth.php (qui était vide jusqu'ici) :
<?php
declare(strict_types=1);
const TOKEN_FICHIER = __DIR__ . '/../data/.api-token';
function token_attendu(): string
{
if (!is_file(TOKEN_FICHIER)) {
// Aucun token défini : on génère, on enregistre, on l'affiche une seule fois
$nouveau = bin2hex(random_bytes(24));
file_put_contents(TOKEN_FICHIER, $nouveau);
// Pour le TP : afficher dans la réponse pour que l'élève le voie une fois
return $nouveau;
}
return trim(file_get_contents(TOKEN_FICHIER));
}
function exiger_token(): void
{
$envoye = $_SERVER['HTTP_X_API_KEY'] ?? '';
$attendu = token_attendu();
// hash_equals : comparaison "à temps constant" résistante aux attaques par chronométrage
if (!is_string($envoye) || !hash_equals($attendu, $envoye)) {
http_response_code(401); // Unauthorized
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['error' => 'Token manquant ou invalide.']);
exit;
}
}
⚠️ Pourquoi
hash_equalset pas===? Parce qu'un===peut être détecté par chronométrage très fin : il s'arrête au premier caractère faux.hash_equalscompare en temps constant, peu importe où est la différence. C'est une bonne habitude dès qu'on compare des secrets.
Dans public/api/report.php, ajoute au tout début (juste après les
headers) :
require __DIR__ . '/../../src/auth.php';
exiger_token();
Et c'est tout. Toute requête sans X-API-Key valide reçoit un 401.
$token = "ABC123ABC123..." # le contenu de data/.api-token
Invoke-RestMethod -Uri $ApiUrl `
-Method Post `
-ContentType "application/json; charset=utf-8" `
-Headers @{ "X-API-Key" = $token } `
-Body $json
💡 Ne mets jamais le token en dur dans le script publié sur GitHub. Stocke-le dans une variable d'environnement Windows et lis-la :
$token = $env:INVENTAIRE_TOKEN if (-not $token) { throw "Token non défini." }
| Cas | Attendu |
|---|---|
POST sans X-API-Key |
401 |
POST avec un X-API-Key faux |
401 |
POST avec le bon X-API-Key |
201 |
| GET sur le dashboard | 200 (lecture libre, on peut décider de protéger plus tard) |
Quand tu travailles sur du code de sécurité, double-vérifie chaque suggestion. L'IA peut :
=== au lieu de hash_equals ;Bon prompt :
Voici mon code de vérification de token. [colle le code] Liste-moi 5 erreurs de sécurité classiques que je pourrais commettre ici, et indique laquelle est présente dans mon code.
C'est une technique très utile : demander à l'IA de chercher des problèmes plutôt que de produire une solution. Tu transformes l'IA en relecteur.
Cette protection est simple mais fragile. Pour vraiment sécuriser une API en production, on ajouterait :
Tout ça est hors-scope pour le TP, mais tu dois pouvoir l'expliquer à l'oral. Si l'examinateur demande « ton API est-elle sécurisée pour la prod ? », la bonne réponse est :
Non, c'est une sécurité minimale par token partagé. Pour la production, il faudrait HTTPS, un token par client, du HMAC, de la rotation et du rate limiting.
Pour chacune des 5 améliorations ci-dessus, demande à l'IA :
Explique-moi en 4 phrases pourquoi un token unique partagé est moins sûr qu'un token par client. Donne-moi un scénario d'attaque concret où la différence est critique.
Tu apprendras plus en posant un pourquoi qu'en demandant un comment.
hash_equals plutôt que ===.| Piège | Solution |
|---|---|
| Token affiché en clair sur le dashboard | Jamais ! Le supprimer du HTML/log |
| Token commité dans Git | Mettre .api-token dans .gitignore |
| Le token change à chaque redémarrage | Le sauvegarder dans un fichier (ce qu'on fait) |
| 401 incompréhensible côté PowerShell | try/catch qui affiche $_.Exception.Response.StatusCode |
À ce stade, tu as :
C'est un vrai mini-produit. Pas un exercice. Pas un jouet.
Tu présentes en 8 minutes :
💡 Conseil final IA : utilise l'IA pour te préparer aux questions du jury, pas pour préparer ton speech. Prompt-type : "Voici mon projet [résumé]. Quelles sont les 5 questions les plus difficiles qu'un jury de prof d'informatique pourrait me poser ?" Si tu sais répondre aux 5, tu passes.
Bon courage !