Pourquoi Rust est-il le choix idéal pour l'authentification ?
\n\nSi vous écrivez une application web en Rust, vous avez déjà une longueur d'avance en matière de sécurité. Rust ne pardonne pas les erreurs de mémoire, ce qui signifie que de nombreuses vulnérabilités (dépassement de tampon, use-after-free) sont éliminées dès la compilation. Mais le compilateur ne vous protégera pas d'une mauvaise logique d'authentification. C'est précisément le sujet de cet article : comment construire une authentification sécurisée en Rust en utilisant les pratiques modernes.
\n\nDans cet article, nous allons assembler un module d'authentification complet : hachage de mots de passe avec bcrypt, émission de jetons JWT, vérification middleware dans Actix-web et protection contre les attaques courantes. Le code sera fonctionnel — n'hésitez pas à l'utiliser dans votre projet.
1. Hachage de mots de passe : pourquoi bcrypt et pas SHA-256 ?
\n\nBeaucoup de débutants pensent : « Je vais prendre SHA-256, c'est rapide et fiable ». Et c'est une erreur fatale. SHA est une fonction de hachage cryptographique, mais elle est trop rapide. Un attaquant peut essayer des milliards de combinaisons par seconde. Nous avons besoin d'une fonction lente, spécialement conçue pour les mots de passe.
\n\nbcrypt est l'étalon-or. Il inclut un « sel » (salt) et un « facteur de coût » (cost factor) que l'on peut augmenter à mesure que la puissance de calcul croît.
\n\nAjout de bcrypt dans Cargo.toml
\n[dependencies]\nbcrypt = "0.15"\n\nHachage du mot de passe
\nuse bcrypt::{hash, verify, DEFAULT_COST};\n\nfn hash_password(plain: &str) -> Result<String, bcrypt::BcryptError> {\n hash(plain, DEFAULT_COST) // cost = 12 (par défaut)\n}\n\nfn verify_password(plain: &str, hashed: &str) -> bool {\n verify(plain, hashed).unwrap_or(false)\n}\n\nNotez que verify extrait lui-même le sel du hachage. Vous n'avez pas besoin de stocker le sel séparément — il est déjà intégré dans la chaîne de hachage. C'est sûr et pratique.
2. Jetons JWT : comment ne pas échouer l'authentification
\n\nUne fois que l'utilisateur a saisi son mot de passe, nous devons lui délivrer un « laissez-passer ». JWT (JSON Web Token) est un format compact et autonome. Mais le diable se cache dans les détails :
\n\n- \n
- Ne stockez pas la clé secrète dans le code. Utilisez des variables d'environnement. \n
- Définissez une durée de vie courte. Jeton d'accès — 15 à 30 minutes, jeton de rafraîchissement — 7 à 30 jours. \n
- N'insérez pas de données sensibles dans le payload. Uniquement l'ID de l'utilisateur et son rôle. \n
Implémentation JWT avec jsonwebtoken
\n\nuse jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};\nuse serde::{Serialize, Deserialize};\nuse chrono::{Utc, Duration};\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct Claims {\n pub sub: String, // ID de l'utilisateur\n pub exp: usize, // timestamp d'expiration\n pub iat: usize, // timestamp d'émission\n}\n\npub fn create_token(user_id: &str, secret: &str) -> Result<String, jsonwebtoken::errors::Error> {\n let now = Utc::now();\n let claims = Claims {\n sub: user_id.to_owned(),\n exp: (now + Duration::minutes(30)).timestamp() as usize,\n iat: now.timestamp() as usize,\n };\n encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes()))\n}\n\npub fn validate_token(token: &str, secret: &str) -> Result<Claims, jsonwebtoken::errors::Error> {\n let token_data = decode::<Claims>(\n token,\n &DecodingKey::from_secret(secret.as_bytes()),\n &Validation::default(),\n )?;\n Ok(token_data.claims)\n}\n\n3. Assemblage : Actix-web + middleware
\n\nMaintenant, connectons le hachage et JWT dans une application web complète avec Actix-web. Écrivons un middleware qui vérifiera le jeton dans chaque requête protégée.
\n\nStructure du projet
\nsrc/\n├── main.rs\n├── auth.rs # hachage, JWT\n├── middleware.rs # vérification du jeton\n└── handlers.rs #