Le contexte
Pour un admin durci, j'ai lié le token JWT à une empreinte navigateur (fingerprint) pour limiter le vol de token. À chaque requête, on revérifie l'empreinte.
Le symptôme
Des utilisateurs déconnectés au bout de quelques minutes, de façon aléatoire. Token pourtant non expiré.
La cause
Le fingerprint incluait des composants instables :
// Mauvais : ces valeurs bougent
const fp = hash([
navigator.userAgent,
window.innerWidth + 'x' + window.innerHeight, // change au resize !
navigator.language,
]);
innerWidth/innerHeight change au moindre redimensionnement → le hash ne correspond plus → rejet.
La solution
Ne garder que des composants stables, et vérifier avec tolérance :
const fp = hash([
navigator.userAgent,
navigator.language,
screen.width + 'x' + screen.height, // resolution ecran, pas la fenetre
navigator.platform,
]);
public function isFingerprintValid(array $tokenFp, array $requestFp): bool
{
foreach (['ua', 'platform'] as $key) {
if (($tokenFp[$key] ?? null) !== ($requestFp[$key] ?? null)) {
return false;
}
}
return true; // les composants secondaires ne bloquent pas
}
Ce que je retiens
- Un fingerprint = uniquement des composants stables.
- Égalité stricte sur des données volatiles = bugs aléatoires garantis.
- Le fingerprint complète, il ne remplace pas, les bonnes pratiques JWT.