Quand ton app Angular SSR fonctionne… mais ne fait plus de SSR

C’est probablement l’un des pièges les plus subtils introduits récemment avec Angular SSR.

Ton application fonctionne.
Les pages s’affichent.
Aucune erreur visible côté utilisateur.

Et pourtant

tu ne fais plus de rendu côté serveur.

Le mécanisme invisible

Lorsqu’un utilisateur appelle une route SSR :

GET /preview
Host: example.com

Angular SSR reconstruit une URL complète en interne :

[https://example.com/preview](https://example.com/preview)

Ce point est fondamental.

Angular ne travaille pas avec des chemins relatifs, mais avec des URLs absolues, construites à partir du Host de la requête.

Le vrai problème : le Host est une donnée utilisateur

Contrairement à ce que beaucoup pensent :

le header HTTP Host n’est pas une source fiable

C’est une simple donnée envoyée par le client.

Un attaquant peut parfaitement faire :

curl https://your-app/preview -H "Host: evil.com"

Et ton serveur recevra :

Host: evil.com

Angular reconstruira alors :

https://evil.com/preview

La faille : SSRF

Ce comportement ouvre la porte à une attaque bien connue :

SSRF — Server Side Request Forgery

Le principe :

  • le serveur fait confiance à une donnée contrôlée par l’utilisateur
  • il construit une URL avec cette donnée
  • il effectue des appels réseau vers cette URL

Conséquences possibles :

  • accès à des services internes
  • accès aux metadata cloud (ex: credentials)
  • exfiltration de données sensibles

Ce qu’Angular a changé

Pour corriger cela, Angular a introduit une protection :

allowedHosts

Le principe est simple :

Host ∈ allowedHosts → SSR autorisé
Host ∉ allowedHosts → SSR bloqué

Le piège : le fallback silencieux

Aujourd’hui, si le host n’est pas autorisé :

❌ SSR désactivé
✅ fallback en CSR

Dans les logs :

Falling back to client side rendering
  • Ton application fonctionne toujours…
  • Mais elle ne fait plus de SSR.

Et demain ?

Angular a annoncé un durcissement :

Host non autorisé → HTTP 400
  • Plus de fallback.
  • Ta requête SSR casse directement.

Conséquence réelle en production

Beaucoup d’applications aujourd’hui :

  • pensent faire du SSR
  • mais servent en réalité du CSR dans certains cas

Exemples fréquents :

  • reverse proxy mal configuré
  • host interne utilisé par le load balancer
  • headers forwardés incorrectement
  • appels internes ou outils de test

La solution

Après mise à jour Angular :

configurer explicitement les hosts autorisés

Exemple :

allowedHosts: [
  'example.com',
  'www.example.com',
  '*.example.com'
]

La vraie leçon (au-delà d’Angular)

Ce problème dépasse Angular.

C’est un problème fondamental du protocole HTTP.

Rappel important

Le Host header n’est pas une garantie d’identité.
C’est une déclaration du client.

Et comme toute déclaration utilisateur :

elle doit être validée.

À retenir

  • SSR = backend → mêmes exigences de sécurité qu’une API
  • ne jamais faire confiance au Host
  • ne jamais construire une URL serveur à partir d’une donnée non validée
  • toujours contrôler les entrées, même au niveau protocolaire

Conclusion

Ce n’est pas un bug Angular.

  • C’est une conséquence directe du design HTTP.

Et c’est exactement pour ça que comprendre HTTP en profondeur n’est pas optionnel.

Le danger n’est pas dans le path. Le danger est dans le Host.