Sécurité (Fast API)
La sécurité dans FastAPI consiste à mettre en place un ensemble de mécanismes et bonnes pratiques pour protéger une API contre les attaques, l’accès non autorisé et les fuites de données.
FastAPI intègre nativement plusieurs outils de sécurité, notamment pour la gestion de l’authentification et de l’autorisation, ce qui facilite la création d’API sécurisées dès le départ.
Cela inclut :
-
Contrôler l’accès aux ressources avec authentification et autorisation.
-
Protéger contre les attaques courantes (injections, XSS, CSRF dans certains cas).
-
Sécuriser la communication entre client et serveur.
Comment ça fonctionne dans FastAPI
Authentification et autorisation
-
FastAPI fournit des classes de sécurité intégrées (
fastapi.security
) :-
OAuth2PasswordBearer pour authentification par token.
-
HTTPBasic pour authentification basique.
-
API Keys via header, query ou cookie.
-
-
Possibilité d’intégrer facilement :
-
JWT (JSON Web Tokens) pour sécuriser les endpoints.
-
OAuth2 et OpenID Connect pour gestion avancée des droits.
-
Protection contre les attaques courantes
-
Injection SQL :
-
Utiliser un ORM comme SQLAlchemy ou Tortoise ORM.
-
-
XSS (Cross-Site Scripting) :
-
Éviter de renvoyer du HTML non échappé.
-
-
CSRF (Cross-Site Request Forgery) :
-
Nécessaire si l’API interagit avec des formulaires via navigateur (FastAPI est souvent utilisé côté API pure, donc moins exposé).
-
-
Limitation de taux (rate limiting) :
-
Utiliser des middlewares externes comme
slowapi
.
-
Sécurisation des communications
-
Forcer l’utilisation de HTTPS (certificat SSL/TLS).
-
Ajouter des en-têtes de sécurité via un middleware (ex. :
Strict-Transport-Security
,X-Frame-Options
). -
Sécuriser les cookies avec :
-
Secure
-
HttpOnly
-
SameSite
.
-
Gestion des erreurs et des logs
-
Ne pas exposer les détails internes dans les réponses d’erreur.
-
Utiliser les exceptions HTTP (
HTTPException
) avec codes clairs (401, 403, 404, etc.). -
Consigner les activités suspectes dans un système de logs.
Exemple conceptuel
-
URL / endpoint :
/users/me
-
Comportement :
-
L’utilisateur doit fournir un token JWT valide dans le header
Authorization
. -
Si le token est absent ou invalide → 401 Unauthorized.
-
Si le token est valide mais sans les permissions requises → 403 Forbidden.
-
Sinon → retour des données de l’utilisateur.
-
-
Protection :
-
Middleware HTTPS + en-têtes sécurisés.
-
Validation stricte des entrées.
-
Bonnes pratiques
-
Utiliser OAuth2 avec JWT pour les API sécurisées.
-
Ne jamais stocker de mots de passe en clair (hash avec
bcrypt
oupasslib
). -
Valider toutes les données entrantes avec Pydantic.
-
Configurer un middleware de sécurité pour ajouter les en-têtes HTTP.
-
Activer les logs pour toute tentative d’accès non autorisée.
Pourquoi c’est important
-
Les API sont souvent exposées publiquement, donc vulnérables aux attaques.
-
Une sécurité robuste protège les données sensibles des utilisateurs et prévient les fuites.
-
Des API sécurisées sont une exigence dans les environnements professionnels (RGPD, normes ISO…).
En résumé
-
FastAPI intègre déjà des outils pour l’authentification et l’autorisation.
-
Utiliser HTTPS et sécuriser les tokens est indispensable.
-
Pydantic aide à valider les données pour éviter les injections.
-
Un bon logging et une gestion stricte des erreurs renforcent la sécurité.
Fonctions :
-
Sécurité avec Fast API
Exemple de code :
from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import HTTPBasic, HTTPBasicCredentials import secrets app = FastAPI() security = HTTPBasic() # Utilisateurs autorisés (nom d'utilisateur: mot de passe) users_db = { "alice": "wonderland", "bob": "builder" } # Fonction pour vérifier les identifiants def get_current_user(credentials: HTTPBasicCredentials = Depends(security)): correct_password = users_db.get(credentials.username) if not correct_password or not secrets.compare_digest(credentials.password, correct_password): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Nom d'utilisateur ou mot de passe incorrect", headers={"WWW-Authenticate": "Basic"}, ) return credentials.username # Route sécurisée @app.get("/secure-data") def read_secure_data(username: str = Depends(get_current_user)): return {"message": f"Bonjour {username}, vous avez accès aux données sécurisées !"}
Explication du code :
from fastapi import FastAPI, Depends, HTTPException, status
importe FastAPI pour créer l’application, Depends pour gérer les dépendances (ici l’authentification), HTTPException pour lever des erreurs HTTP et status pour utiliser des codes de statut standardisés.from fastapi.security import HTTPBasic, HTTPBasicCredentials
importe HTTPBasic pour l’authentification basique HTTP et HTTPBasicCredentials pour représenter les identifiants fournis par l’utilisateur.import secrets
importe le module secrets pour comparer les mots de passe de façon sécurisée et éviter les attaques par timing.Créer l’application FastAPI
app = FastAPI()
crée une instance de l’application FastAPI.
security = HTTPBasic()
initialise l’authentification basique pour l’utiliser comme dépendance.Définir la base d’utilisateurs
users_db = {"alice": "wonderland", "bob": "builder"}
crée un dictionnaire simulant une base de données d’utilisateurs avec leurs mots de passe.Vérification des identifiants
def get_current_user(credentials: HTTPBasicCredentials = Depends(security)):
définit une fonction qui sera utilisée comme dépendance pour sécuriser les routes.
credentials
contient le nom d’utilisateur et le mot de passe envoyés par l’utilisateur.correct_password = users_db.get(credentials.username)
récupère le mot de passe associé à l’utilisateur.
if not correct_password or not secrets.compare_digest(credentials.password, correct_password):
vérifie que le mot de passe est correct de manière sécurisée.
raise HTTPException(...)
lève une erreur HTTP 401 si les identifiants sont incorrects et ajoute l’en-têteWWW-Authenticate
pour indiquer qu’une authentification est requise.return credentials.username
retourne le nom d’utilisateur si l’authentification est réussie.Route sécurisée
@app.get("/secure-data")
définit une route GET sécurisée.
username: str = Depends(get_current_user)
indique que la route dépend de la fonction d’authentification ; seuls les utilisateurs authentifiés y accèdent.
return {"message": f"Bonjour {username}, vous avez accès aux données sécurisées !"}
renvoie un message personnalisé à l’utilisateur authentifié.