Interceptors, guards, gestion des tokens, erreurs HTTP et sanitization : les bonnes pratiques Angular pour sécuriser les échanges avec votre API.
Responsabilites frontend vs backend
Une idee recue frequente est de penser qu'une application Angular "securisee" est une application qui ne se fait pas pirater. En realite, la securite se partage strictement entre le frontend et le backend, et confondre les deux responsabilites cree des failles directes en production.
Ce qu'Angular protege nativement
Le moteur de template Angular echappe automatiquement les valeurs interpolees via {{ }} et les bindings de propriete comme [textContent].
Cela elimine la grande majorite des attaques XSS par injection de scripts dans le DOM.
{{ userInput }} dans un template Angular, la valeur est systematiquement echappee.
Un attaquant injectant <script>alert(1)</script> verra son code affiche comme texte brut, pas execute.
Ce qu'Angular ne protege pas
Angular ne fait aucune validation d'autorisation metier. Il n'empeche pas un utilisateur connecte d'appeler directement une URL d'API avec les bons parametres. Il ne protege pas contre les injections SQL, les attaques SSRF ou les acces non autorises aux ressources d'autres utilisateurs (IDOR).
curl ou Postman.
Cartographie des menaces OWASP
Le tableau ci-dessous resume les 6 menaces les plus courantes dans les SPA Angular, en precisant ou chaque defense doit etre implementee.
| Menace OWASP | Gravite | Role du frontend Angular | Role du backend |
|---|---|---|---|
| XSS — Injection de script | Critique | Echappement automatique des bindings, eviter [innerHTML] |
Sanitization des sorties HTML, headers CSP |
| Broken Access Control (IDOR) | Critique | Guard UI (experience utilisateur uniquement) | Verification d'autorisation sur chaque endpoint |
| Injection SQL / NoSQL | Critique | Aucun (le frontend n'accede pas a la BDD) | Requetes parametrees, ORM, validation des entrees |
| Broken Authentication | Eleve | Interceptor, logout propre, expiration token | Validation JWT, rotation des tokens, revocation |
| CSRF | Eleve | Eviter cookies persistants pour les tokens | Token CSRF, validation Origin/Referer, SameSite |
| Exposition de donnees sensibles | Eleve | Ne pas logguer de donnees sensibles en console | Chiffrement, masquage des champs, HTTPS obligatoire |
Gestion securisee des tokens JWT
Le stockage des tokens d'authentification est l'un des sujets les plus debattus en securite SPA. Il n'existe pas de solution parfaite : chaque approche implique des compromis entre securite, commodite et complexite d'implementation.
Tableau comparatif des 3 approches de stockage
| Stockage | Accessible par JS | Risque XSS | Risque CSRF | Recommande pour |
|---|---|---|---|---|
localStorage |
Oui | Critique | Non | A eviter pour les tokens sensibles |
sessionStorage |
Oui | Critique | Non | Sessions courtes et non critiques |
Cookie HttpOnly |
Non | Nul | Possible (mitiger avec SameSite=Strict) | Meilleure option avec backend cooperatif |
Decoder un JWT sans librairie externe
Il est parfois utile de lire l'expiration d'un token cote client sans dependre d'une librairie tierce. Le payload d'un JWT est un objet JSON encode en Base64Url. Cette fonction utilitaire permet de le decoder et de verifier si le token est expire avant de declencher une requete API.
// utils/jwt.utils.ts
/**
* Decode le payload d'un JWT sans verification de signature.
* ATTENTION : ne jamais faire confiance aux donnees d'un JWT
* sans validation cote serveur. Cette fonction sert uniquement
* a lire l'expiration pour l'UX (redirection preventive).
*/
export function decodeJwtPayload(token: string): Record<string, unknown> | null {
try {
// Le payload est la 2eme partie du JWT (index 1) separee par des points
const base64Url = token.split('.')[1];
// Convertir Base64Url en Base64 standard puis decoder
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
return JSON.parse(atob(base64));
} catch {
return null;
}
}
/**
* Retourne true si le token est expire ou invalide.
* La propriete `exp` dans le payload JWT est un timestamp Unix en secondes.
*/
export function isTokenExpired(token: string | null): boolean {
if (!token) return true;
const payload = decodeJwtPayload(token);
if (!payload || typeof payload['exp'] !== 'number') return true;
// Date.now() est en millisecondes, exp est en secondes
return Date.now() >= (payload['exp'] as number) * 1000;
}
Duree de vie courte et refresh token
Quelle que soit l'approche de stockage, un access token doit avoir une duree de vie courte (5 a 15 minutes). Le refresh token peut vivre plus longtemps, mais doit etre stocke de facon securisee (cookie HttpOnly de preference) et revoque cote serveur lors du logout.
Strategie de logout securisee
Un logout fiable doit agir sur les deux extremites : cote client (vider les tokens) ET cote serveur (revoquer le refresh token). Se contenter du cote client laisse le refresh token valide jusqu'a son expiration naturelle.
// services/auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { Observable, map, tap } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class AuthService {
private readonly TOKEN_KEY = 'access_token';
private readonly REFRESH_KEY = 'refresh_token';
constructor(private http: HttpClient, private router: Router) {}
/** Recupere l'access token stocke en localStorage */
getAccessToken(): string | null {
return localStorage.getItem(this.TOKEN_KEY);
}
/** Appelle le backend pour obtenir un nouveau access token via le refresh token */
refreshToken(): Observable<string> {
const refreshToken = localStorage.getItem(this.REFRESH_KEY);
return this.http
.post<{ access_token: string }>('/api/auth/refresh', { refreshToken })
.pipe(
// Persister le nouveau access token et retourner sa valeur
tap(res => localStorage.setItem(this.TOKEN_KEY, res.access_token)),
map(res => res.access_token)
);
}
/**
* Logout complet (3 etapes) :
* 1. Notifie le backend pour revoquer le refresh token en base
* 2. Vide les tokens du stockage local
* 3. Redirige vers la page de connexion
*/
logout(): void {
const refreshToken = localStorage.getItem(this.REFRESH_KEY);
// Appel non bloquant : on logout meme si la requete echoue
this.http.post('/api/auth/logout', { refreshToken }).subscribe();
localStorage.removeItem(this.TOKEN_KEY);
localStorage.removeItem(this.REFRESH_KEY);
this.router.navigateByUrl('/login');
}
}
Intercepteurs HTTP : auth et refresh token
Depuis Angular 15, les intercepteurs peuvent etre de simples fonctions (HttpInterceptorFn) au lieu de classes implementant HttpInterceptor.
Ce style fonctionnel est plus leger, facilement testable et parfaitement compatible avec l'injection de dependances via inject().
Intercepteur complet avec retry automatique sur 401
Cet intercepteur couvre les trois besoins essentiels : ajout du header Authorization,
gestion du refresh automatique sur les reponses 401, et possibilite de marquer certaines routes comme publiques
pour ne pas leur attacher le token.
// interceptors/auth.interceptor.ts
import {
HttpContextToken,
HttpErrorResponse,
HttpInterceptorFn,
HttpContext
} from '@angular/common/http';
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { catchError, switchMap, throwError } from 'rxjs';
import { AuthService } from '../services/auth.service';
/**
* HttpContextToken pour marquer les routes publiques.
* Valeur par defaut : false (toutes les routes sont protegees).
* Usage dans un service : withContext(new HttpContext().set(IS_PUBLIC, true))
*/
export const IS_PUBLIC = new HttpContextToken<boolean>(() => false);
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const auth = inject(AuthService);
const router = inject(Router);
// ── 1. Ignorer les routes marquees comme publiques ──────────────────
if (req.context.get(IS_PUBLIC)) {
return next(req);
}
// ── 2. Ajouter le header Authorization si un token est disponible ──
const token = auth.getAccessToken();
const authReq = token
? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } })
: req;
// ── 3. Intercepter les 401 pour tenter un refresh automatique ───────
return next(authReq).pipe(
catchError((err: HttpErrorResponse) => {
// Eviter une boucle infinie si la route de refresh elle-meme renvoie 401
if (err.status === 401 && !req.url.includes('/auth/refresh')) {
return auth.refreshToken().pipe(
switchMap(newToken => {
// Retenter la requete originale avec le nouveau token
const retryReq = req.clone({
setHeaders: { Authorization: `Bearer ${newToken}` }
});
return next(retryReq);
}),
catchError(refreshErr => {
// Le refresh a echoue → logout complet et redirection vers login
auth.logout();
router.navigate(['/login'], { state: { returnUrl: router.url } });
return throwError(() => refreshErr);
})
);
}
// Propager toutes les autres erreurs sans interception
return throwError(() => err);
})
);
};
Enregistrement dans le bootstrap de l'application
L'intercepteur doit etre enregistre via provideHttpClient(withInterceptors([...])).
L'ordre dans le tableau definit l'ordre d'execution (le premier est le plus externe, comme un oignon).
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideRouter } from '@angular/router';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
import { authInterceptor } from './app/core/interceptors/auth.interceptor';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
// authInterceptor sera execute sur toutes les requetes HttpClient
provideHttpClient(withInterceptors([authInterceptor]))
]
}).catch(console.error);
Marquer une route comme publique avec HttpContextToken
Le IS_PUBLIC token permet d'indiquer a l'intercepteur de sauter l'ajout du header
Authorization sur certaines requetes : authentification, assets publics, endpoints sans restriction, etc.
// services/auth-api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpContext } from '@angular/common/http';
import { IS_PUBLIC } from '../interceptors/auth.interceptor';
@Injectable({ providedIn: 'root' })
export class AuthApiService {
constructor(private http: HttpClient) {}
login(credentials: { email: string; password: string }) {
return this.http.post('/api/auth/login', credentials, {
// Marquer comme public : authInterceptor ne ajoutera pas de token
context: new HttpContext().set(IS_PUBLIC, true)
});
}
register(data: { email: string; password: string; name: string }) {
return this.http.post('/api/auth/register', data, {
context: new HttpContext().set(IS_PUBLIC, true)
});
}
}
Guards : protection des routes
Les guards Angular controlent l'acces aux routes de l'application. Ils sont essentiels pour l'experience utilisateur (eviter d'afficher un tableau de bord a un visiteur non connecte), mais ils ne remplacent jamais les verifications d'autorisation cote serveur.
Guard fonctionnel avec verification d'expiration
Depuis Angular 14, les guards peuvent etre de simples fonctions. Ce guard verifie non seulement la presence du token, mais aussi s'il est encore valide (non expire), evitant d'afficher une page qui genererait immediatement une erreur 401.
// guards/auth.guard.ts
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
import { isTokenExpired } from '../utils/jwt.utils';
/**
* Guard qui protege les routes necessitant une authentification.
* Verifie :
* 1. La presence d'un token en localStorage
* 2. Que le token n'est pas expire (verification cote client)
* En cas d'echec, redirige vers /login avec l'URL originale en state
* pour pouvoir y revenir apres connexion reussie.
*/
export const authGuard: CanActivateFn = (route, state) => {
const router = inject(Router);
const token = localStorage.getItem('access_token');
if (!token || isTokenExpired(token)) {
router.navigate(['/login'], {
// Memoriser l'URL cible pour rediriger apres le login
state: { returnUrl: state.url }
});
return false;
}
return true;
};
Revenir a l'URL d'origine apres connexion
Le composant de login peut recuperer l'URL de retour depuis le state de navigation, puis rediriger l'utilisateur vers sa destination initiale apres connexion reussie.
// components/login/login.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({ selector: 'app-login', templateUrl: './login.component.html' })
export class LoginComponent implements OnInit {
// URL par defaut si aucune destination n'a ete memorisee
private returnUrl = '/dashboard';
constructor(private router: Router) {}
ngOnInit(): void {
// Recuperer l'URL de retour depuis le state de la navigation entrante
const nav = this.router.getCurrentNavigation();
const state = nav?.extras?.state as { returnUrl?: string } | undefined;
if (state?.returnUrl) {
this.returnUrl = state.returnUrl;
}
}
onLoginSuccess(): void {
// Rediriger vers l'URL memorisee au lieu du dashboard generique
this.router.navigateByUrl(this.returnUrl);
}
}
Guard de role pour l'autorisation par profil
Un guard peut aussi verifier le role de l'utilisateur encode dans le JWT. Ce pattern de guard en fabrique accepte une liste de roles autorises en parametre. Rappel : cette verification est purement UX — le backend doit imperativement verifier le role sur chaque endpoint protege.
// guards/role.guard.ts
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
import { decodeJwtPayload } from '../utils/jwt.utils';
/**
* Fabrique de guard qui accepte un ou plusieurs roles autorises.
* Exemple d'utilisation dans app.routes.ts :
* { path: 'admin', canActivate: [roleGuard('admin', 'superadmin')] }
*/
export function roleGuard(...allowedRoles: string[]): CanActivateFn {
return (route, state) => {
const router = inject(Router);
const token = localStorage.getItem('access_token');
if (!token) {
router.navigate(['/login'], { state: { returnUrl: state.url } });
return false;
}
const payload = decodeJwtPayload(token);
const userRole = payload?.['role'] as string | undefined;
if (!userRole || !allowedRoles.includes(userRole)) {
// Token present mais role insuffisant → page acces refuse
router.navigateByUrl('/forbidden');
return false;
}
return true;
};
}
XSS et DomSanitizer
Angular protege automatiquement les templates contre les attaques XSS pour la grande majorite des cas d'usage. Mais certains scenarios necessitent une vigilance particuliere : l'affichage de HTML dynamique, d'URLs calculees ou de styles inlines provenant de sources externes.
Ce qu'Angular echappe automatiquement
Tous les bindings de texte sont echappes par defaut. Il n'y a rien a faire de special pour se proteger dans les cas standards.
<!-- Angular echappe ces bindings automatiquement ──────────────────────── -->
<!-- Interpolation : le contenu est converti en entites HTML -->
<p>{{ userInput }}</p>
<!-- Property binding sur textContent : meme protection -->
<p [textContent]="userInput"></p>
<!-- Valeur d'input : echappee aussi -->
<input [value]="userInput" />
Les trois cas dangereux a surveiller
Trois contextes demandent une attention particuliere car Angular ne peut pas echapper leur contenu sans en changer la semantique voulue.
<!-- DANGER 1 : [innerHTML] interprete le HTML brut ────────────────────── -->
<!-- Si userHtml contient <script>, il sera execute dans certains contextes -->
<div [innerHTML]="userHtml"></div>
<!-- DANGER 2 : [href] peut contenir un vecteur javascript: ────────────── -->
<!-- Angular bloque javascript: mais certaines variantes encodees passent -->
<a [href]="dynamicUrl">Lien externe</a>
<!-- DANGER 3 : style dynamique avec URL externe ───────────────────────── -->
<div [style.backgroundImage]="'url(' + userUrl + ')'"></div>
DomSanitizer : quand c'est risque et quand c'est acceptable
DomSanitizer expose des methodes bypassSecurityTrust* qui desactivent explicitement les protections Angular.
Ces methodes ne doivent etre utilisees que lorsque la source du contenu est absolument fiable et sous votre controle.
// MAUVAISE pratique : contourner la securite sur du contenu utilisateur ──
import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Component({
template: '<div [innerHTML]="trustedHtml"></div>'
})
export class DangerousComponent {
trustedHtml: SafeHtml;
constructor(private sanitizer: DomSanitizer) {
// NE JAMAIS faire cela avec du contenu soumis par un utilisateur
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml(userProvidedHtml);
}
}
// BONNE pratique : nettoyer d'abord avec DOMPurify ───────────────────────
// Installation : npm install dompurify && npm install -D @types/dompurify
import DOMPurify from 'dompurify';
import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Component({
template: '<div [innerHTML]="safeHtml"></div>'
})
export class SafeCmsComponent {
safeHtml: SafeHtml;
constructor(private sanitizer: DomSanitizer) {
// DOMPurify supprime les balises et attributs dangereux avant affichage
const cleaned = DOMPurify.sanitize(cmsHtmlContent, {
ALLOWED_TAGS: ['p', 'ul', 'ol', 'li', 'strong', 'em', 'a', 'h2', 'h3', 'code', 'pre'],
ALLOWED_ATTR: ['href', 'target', 'rel']
});
// On peut maintenant marquer le contenu comme de confiance
this.safeHtml = this.sanitizer.bypassSecurityTrustHtml(cleaned);
}
}
- Nettoyer le HTML cote serveur (recommande) ou via DOMPurify cote client.
- Definir une liste blanche stricte des balises et attributs autorises.
- Documenter chaque usage de
bypassSecurityTrustHtmlavec la justification dans un commentaire. - Mettre en place des tests de regression XSS sur les zones a risque (Playwright, Cypress).
Variables d'environnement et secrets
Le fichier environment.ts d'Angular est souvent mal utilise. Il est compile dans le bundle JavaScript final,
ce qui signifie que tout ce qu'il contient est lisible par n'importe qui qui inspecte le code source de l'application en production.
Ce qui peut aller dans environment.ts
// environments/environment.prod.ts
// Ce fichier est remplace au moment du build par Angular CLI (fileReplacements)
export const environment = {
production: true,
// URL de l'API : visible dans le bundle, c'est acceptable
apiUrl: 'https://api.monapp.com',
// Feature flags : visibles mais non sensibles
enableAnalytics: true,
showDebugPanel: false,
// Cle publique Stripe / Firebase : concues pour etre publiques.
// La securite repose sur les regles cote serveur, pas sur la cle elle-meme.
stripePublishableKey: 'pk_live_...'
};
Ce qui ne doit JAMAIS etre dans le bundle
environment.ts
ni dans aucun fichier TypeScript compile dans le bundle frontend. Ils seraient lisibles par tout le monde.
// INTERDIT dans environment.ts ──────────────────────────────────────────
// Cle privee API (Stripe, Twilio, SendGrid, AWS...)
stripeSecretKey: 'sk_live_...', // INTERDIT — rester cote serveur
// Credentials de base de donnees
dbPassword: 'monpassword', // INTERDIT
// JWT secret pour signer les tokens
jwtSecret: 'supersecretjwt', // INTERDIT
// Cles d'API sans restriction de domaine (a proxifier via backend)
openaiApiKey: 'sk-...', // INTERDIT
// Chaine de connexion avec identifiants
mongoUri: 'mongodb+srv://user:pass@...' // INTERDIT
Variables d'environnement CI/CD
Pour les URLs et identifiants publics qui varient selon l'environnement (dev, staging, prod), la bonne pratique est de les injecter au moment du build via les variables d'environnement du systeme CI/CD.
# GitHub Actions — exemple d'injection de variables au build
- name: Build Angular
run: ng build --configuration=production
env:
# Ces variables sont injectees via les Secrets GitHub Actions
# et remplacent les placeholders dans environment.prod.ts
API_URL: ${{ secrets.PROD_API_URL }}
STRIPE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }}
Content Security Policy (CSP)
Une CSP correctement configuree est le dernier rempart contre les attaques XSS qui auraient echappe aux autres mecanismes. Elle est configuree cote serveur (header HTTP) et indique au navigateur quelles sources de contenu sont autorisees.
# Exemple de header CSP pour une application Angular (Nginx)
# A placer dans la configuration du serveur web en production
add_header Content-Security-Policy "
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;
connect-src 'self' https://api.monapp.com;
frame-ancestors 'none';
" always;
'unsafe-inline' pour les styles est souvent necessaire avec Angular (styles encapsules).
En production avancee, privilegiez les nonces CSP pour eliminer aussi ce vecteur residuel.
CORS : ce qu'Angular fait (et ne fait pas)
Les erreurs CORS sont parmi les plus deroutantes pour les developpeurs Angular debutants. Il est important de comprendre que CORS est une politique du navigateur, pas une fonctionnalite d'Angular. Le framework ne peut ni l'activer ni le desactiver.
Le proxy de developpement Angular CLI
En developpement, l'application Angular tourne sur localhost:4200 et l'API sur un port different
ou une URL distante. Le serveur de dev Angular CLI peut faire office de proxy pour eviter les erreurs CORS
localement, sans modifier le backend.
// proxy.conf.json — a placer a la racine du projet Angular
{
"/api": {
// Toutes les requetes vers /api seront proxifiees vers ce serveur
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true,
"logLevel": "debug"
},
"/auth": {
"target": "https://api.monapp.com",
"secure": true,
"changeOrigin": true,
// Recrire le prefixe du chemin si l'API distante utilise une autre base
"pathRewrite": {
"^/auth": "/v1/auth"
}
}
}
// angular.json — enregistrer le proxy dans la configuration de serve
{
"projects": {
"mon-app": {
"architect": {
"serve": {
"options": {
"proxyConfig": "proxy.conf.json"
}
}
}
}
}
}
proxy.conf.json comme solution de production.
Configuration CORS cote serveur (Nginx)
En production, les headers CORS doivent etre configures sur le serveur backend. Voici un exemple Nginx minimal pour une API REST consommee par une application Angular.
# nginx.conf — configuration CORS pour une API REST consommee par Angular
location /api {
# Toujours specifier une origine precise en production (jamais *)
add_header Access-Control-Allow-Origin "https://www.monapp.com" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
add_header Access-Control-Allow-Credentials "true" always;
# Repondre immediatement aux preflight OPTIONS sans passer au backend
if ($request_method = OPTIONS) {
return 204;
}
}
Les erreurs CORS les plus frequentes
| Erreur navigateur | Cause probable | Solution |
|---|---|---|
| No 'Access-Control-Allow-Origin' header | Le backend n'envoie pas le header | Configurer les headers CORS sur le serveur web ou le framework backend |
| Header not allowed in preflight | Authorization absent de Allow-Headers |
Ajouter Authorization a la liste Access-Control-Allow-Headers |
| Credentials flag is 'true' but CORS header is '*' | withCredentials: true avec Allow-Origin: * |
Specifier une origine precise et ajouter Access-Control-Allow-Credentials: true |
Checklist securite production
Avant de deployer une application Angular en production, voici les points de securite a valider systematiquement. Cette checklist couvre le frontend, la configuration serveur et les bonnes pratiques de code.
Frontend Angular
- Tous les tokens sont geres via un service dedie (pas directement dans les composants).
- Un intercepteur centralise ajoute les headers d'authentification sur toutes les requetes protegees.
- La gestion du 401 est implementee : refresh automatique ou logout + redirection.
- Les routes sensibles sont protegees par des guards fonctionnels (
CanActivateFn). - Aucun usage de
[innerHTML]sans DOMPurify ou sanitization serveur. - Aucun secret (cle API privee, mot de passe, JWT secret) present dans
environment.ts. - Le logout vide tous les tokens cote client ET envoie une requete de revocation au backend.
- Les erreurs HTTP ne loggent pas de donnees sensibles en console (tokens, PII).
Configuration serveur et infrastructure
- HTTPS obligatoire sur tous les endpoints avec redirection HTTP → HTTPS.
- Headers de securite configures : CSP, X-Frame-Options, X-Content-Type-Options.
- CORS restreint aux origines connues (jamais
*en production avec credentials). - Cookies d'authentification avec
HttpOnly,SecureetSameSite=Strict. - Access tokens avec une duree de vie courte (5 a 15 minutes maximum).
- Dependances auditees regulierement avec
npm auditet mises a jour d'Angular.
Tableau de synthese : menace → ou traiter → comment
| Menace | Ou traiter | Comment |
|---|---|---|
| XSS | Frontend + backend | Bindings Angular + DOMPurify + header CSP |
| Acces non autorise (IDOR) | Backend uniquement | Verification d'autorisation sur chaque endpoint |
| Token vole via XSS | Frontend + backend | Cookie HttpOnly + rotation frequente + revocation |
| Session hijacking | Backend + infrastructure | HTTPS strict + tokens courte duree + fingerprinting |
| Secrets exposes dans le bundle | Backend + CI/CD | Variables d'env CI/CD, vault, revue de code obligatoire |
| CORS mal configure | Backend | Origines whitelistees, preflight correct, pas de wildcard |
npm audit), maintenez Angular a jour et revoyez
votre configuration CORS et CSP a chaque evolution de l'architecture.