🛡️ NetScaler · Sécurité · CSP

Gestion des CSP Headers sur Citrix NetScaler

✍️ Jérôme Dellacasa — Elyleo ⏱️ ~14 min de lecture 🏷️ NetScaler · CSP · Rewrite · Gateway · Sécurité

En bref — Le Content-Security-Policy (CSP) est un header HTTP essentiel contre les attaques XSS. Sur NetScaler il intervient à plusieurs niveaux : pages natives de la Gateway, applications proxifiées via Rewrite Policies, module WAF. Depuis les builds 14.1-47.46 / 13.1-59.19, Citrix l’active par défaut — au prix de cassures d’authentification SAML/DUO. La bonne approche : garder la CSP par défaut, la remplacer à la demande par Gateway via une rewrite conditionnelle, puis valider avec le CSP Evaluator. Cet article décortique le fonctionnement, analyse une CSP Gateway réelle directive par directive, et fournit des configurations prêtes à l’emploi.

La CSP par défaut de NetScaler, tel un videur qui bloque le pirate XSS mais aussi l'invité légitime SAML/DUO

1. Pourquoi cet article

Suite à plusieurs tests de sécurité (pentests) réalisés sur des gateways Citrix que j’administre pour mes clients, j’ai reçu des retours récurrents concernant les Content-Security-Policy headers : CSP absents, trop permissifs, ou mal configurés. Les rapports remontaient systématiquement ces findings, et les équipes sécurité demandaient des corrections — sans toujours comprendre ce que NetScaler faisait réellement avec ces headers, ni quelles corrections étaient légitimes.

Puis, avec les builds 14.1-47.46 et 13.1-59.19 (correctif des CVE-2025-5777 et CVE-2025-6543), Citrix a activé le CSP header par défaut sur toutes les réponses générées par la Gateway et les vServers d’authentification. Démarche « secure by default » louable, mais qui a provoqué des cassures d’authentification SAML chez de nombreux clients : pages de login « cassées », redirections IDP bloquées, intégrations DUO non fonctionnelles (voir CTX694826).

Résultat : des ouvertures de tickets en urgence, des rollbacks de firmware, et beaucoup de confusion entre équipes infra (« c’est le NetScaler qui bloque ») et équipes sécu (« il faut un CSP strict »). Cet article clarifie la situation :

  1. Comprendre ce que fait l’activation CSP par défaut (set aaa parameter -defaultCSPHeader ENABLE) et ce qu’elle ne fait pas.
  2. Identifier les problèmes que ça cause (SAML, IDP tiers, scripts custom sur la page de login).
  3. Implémenter une CSP personnalisée pour une Gateway/vServer donné, différente de la politique par défaut.
  4. Ajouter des CSP sur vos applications backend qui n’en ont pas, via Rewrite Policies.

2. Ce que fait l’activation CSP par défaut (et ce qu’elle casse)

Depuis les builds 14.1-47.46 / 13.1-59.19, le paramètre defaultCSPHeader est activé par défaut. Concrètement :

  • NetScaler injecte un header Content-Security-Policy sur toutes les pages qu’il génère lui-même : page de login, portail VPN, pages d’erreur, réponses AAA.
  • La politique par défaut est restrictive : default-src 'self' avec des exceptions limitées.
  • Toute ressource externe (scripts IDP, iframes SAML, redirections DUO, scripts reCAPTCHA) non whitelistée est bloquée par le navigateur.

Les symptômes typiques

  • Page de login qui « ne charge pas » ou s’affiche sans styles/scripts.
  • Authentification SAML qui boucle ou échoue silencieusement (redirection IDP bloquée par frame-ancestors ou form-action).
  • iframe DUO qui ne s’affiche plus.
  • reCAPTCHA invisible qui ne se charge pas.

Désactiver (seulement si nécessaire)

NetScaler CLIDésactivation temporaire
set aaa parameter -defaultCSPHeader DISABLE
save config
flush cache contentgroup ALL

Cela résout le problème immédiatement mais vous laisse sans protection CSP sur vos pages Gateway. À réserver au déblocage en urgence.

💡 La bonne approche : garder la défaut, remplacer à la demande

✅ Garder le CSP par défaut
  • Base saine, « secure by default »
  • On ne touche rien tant que ça ne casse pas
  • Activé partout par le firmware
🛠️ Remplacer à la demande
  • Si casse SAML / IDP / double-auth
  • Ou pour durcir une Gateway précise
  • Rewrite conditionnelle (replace + .EXISTS)

Dans la majorité des cas, gardez le CSP par défaut activé. N’intervenez que sur demande, par Gateway/vServer : quand le défaut casse quelque chose (SAML, IDP tiers, double authentification à débugger), ou pour durcir une Gateway. Plutôt que de désactiver globalement puis réinjecter, l’approche la plus propre est de remplacer le header CSP existant via une Rewrite Policy conditionnelle — vous conservez le « secure by default » partout ailleurs. Validez ensuite avec le CSP Evaluator (section dédiée).

3. Qu’est-ce qu’un CSP Header ?

Le Content-Security-Policy est un header HTTP envoyé par le serveur au navigateur. C’est toujours le serveur qui l’émet — dans notre cas le NetScaler, jamais le client. Le navigateur se contente de l’appliquer. Son rôle : restreindre les sources depuis lesquelles le navigateur est autorisé à charger des ressources (scripts, images, styles, iframes…), ce qui protège notamment contre les attaques XSS.

4. Comment NetScaler gère les CSP Headers

NetScaler (ADC) peut intervenir sur les CSP de plusieurs façons :

  • En reverse proxy : laisser passer les CSP du backend, en injecter, ou supprimer les existants via Rewrite Policies.
  • Via le module WAF (AppFirewall) : interaction dans une logique de protection applicative.
  • Via les Rewrite Policies : mécanisme le plus courant pour ajouter/remplacer un CSP côté NetScaler sur les applications proxifiées et les gateways.

CSP « par défaut » de NetScaler Gateway

La CSP par défaut s’applique uniquement aux pages servies directement par NetScaler : page de login, portail VPN, pages d’erreur. Elle ne s’applique pas aux applications backend proxifiées. En cas de double CSP (NetScaler + backend), le navigateur applique les deux simultanément : seule l’intersection la plus restrictive est retenue, ce qui peut provoquer des blocages inattendus — et empêcher la prise en compte d’une CSP spécifique à une Gateway si une CSP par défaut est active. Au debug, le navigateur affiche les deux politiques, mais une seule est réellement appliquée.

Tous les clients ne fournissent pas de CSP

C’est l’un des problèmes de sécurité les plus répandus : les applis modernes bien configurées fournissent leur propre CSP strict ; les applis legacy n’en ont souvent aucun ; les applis tierces ont parfois des CSP trop permissifs (ex. default-src *). NetScaler permet d’ajouter ou renforcer des CSP de façon centralisée via Rewrite Policies, sans modifier les backends.

5. Analyse d’une CSP Citrix Gateway réelle

Voici une CSP typique d’une gateway Citrix avec reCAPTCHA, directive par directive.

default-src 'self'

Règle de fallback. Toute ressource non couverte par une directive spécifique ne peut être chargée que depuis le domaine lui-même.

script-src

  • Autorise le reCAPTCHA Google (google.com/recaptcha, gstatic.com/recaptcha).
  • 'unsafe-inline' : autorise les scripts inline — risque XSS.
  • 'unsafe-eval' : autorise eval() — risque XSS.

Ces deux directives affaiblissent la protection CSP mais sont souvent imposées par des composants Citrix ou le reCAPTCHA.

connect-src 'self'

Restreint les appels réseau (fetch, XHR, WebSocket) au seul domaine. Aucune API externe appelable.

img-src

Très permissif : autorise http: et https: en général, ainsi que le base64 (data:). Le http://localhost:* est lié à des besoins internes Citrix.

style-src 'self' 'unsafe-inline'

Autorise les styles du domaine et les styles inline, souvent nécessaires aux composants Citrix.

font-src 'self' data:

Autorise les polices du domaine et les polices embarquées en base64.

form-action 'self'

Les formulaires ne peuvent soumettre qu’au domaine. Protège contre les redirections malveillantes.

object-src 'none'

Interdit tous les plugins (Flash, Java…). Bonne pratique.

report-uri /nscsp_violation/report_uri

Toute violation est reportée à NetScaler via cet endpoint natif, analysable dans Citrix ADM / NetScaler Console.

6. Les schémas d’URI propriétaires Citrix dans frame-src

La directive frame-src contient des schémas d’URI propriétaires Citrix qui ne sont pas des URLs web classiques. Ils fonctionnent comme des protocol handlers enregistrés sur le poste client (comme mailto: ou tel:), installés avec la Citrix Workspace App. Le navigateur délègue alors au système, qui lance l’application Citrix.

SchémaRôle
receiver://Ancien schéma Citrix Receiver, maintenu pour rétrocompatibilité
citrixng://Schéma Citrix Workspace App (« next generation »)
com.citrix.agmacepa://Déclenchement du scan EPA (End Point Analysis)
com.citrix.nsgclient://Client VPN NetScaler Gateway (tunnel complet)
nsgcepa://Variante du client EPA NetScaler Gateway
application://Schéma générique pour lancer des applications locales

Sans ces entrées, le navigateur bloquerait toute tentative de la page Gateway de déclencher ces protocoles. Ils sont le pont entre l’interface web de la Gateway et le client natif installé sur le poste.

7. Implémenter une CSP personnalisée sur un Gateway vServer (SAML / DUO)

C’est le scénario le plus courant post-mise à jour : le CSP par défaut casse votre authentification (SAML, IDP tiers, DUO), ou vous voulez durcir une Gateway. Deux approches, toutes deux via des Rewrite Policies liées au VPN vServer en mode RESPONSE (on cible les pages générées par la Gateway, pas un LB vServer) :

  • Recommandé — remplacer le CSP par défaut, conditionnellement : on garde le defaultCSPHeader activé et on remplace le header sur la Gateway concernée, sans désactivation globale.
  • Alternative — désactiver puis réinjecter : si vous préférez repartir d’une page « propre », désactivez le CSP global et injectez le vôtre.

Étape 1 (recommandé) — Remplacer le CSP par défaut, conditionnellement

On garde le CSP par défaut activé et on le remplace uniquement sur la Gateway voulue, lorsqu’il est présent. Action replace + policy conditionnée sur .EXISTS :

NetScaler CLIRemplacement conditionnel (recommandé)
add rewrite action rw_act_replace_csp replace "HTTP.RES.HEADER(\"Content-Security-Policy\")" q{"default-src 'self'; script-src https://www.google.com/recaptcha/api.js https://www.gstatic.com/recaptcha/releases/ https://gateway.example.com 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; img-src 'self' data: http: https:; style-src 'self' 'unsafe-inline'; font-src 'self' data:; frame-src https://www.google.com/recaptcha/ com.citrix.agmacepa://* receiver://* citrixng://* com.citrix.nsgclient://* nsgcepa://* application://* 'self'; child-src 'self' com.citrix.agmacepa://* receiver://* citrixng://* com.citrix.nsgclient://* nsgcepa://nsgcepa application://*; form-action 'self'; object-src 'none'; report-uri /nscsp_violation/report_uri"}

add rewrite policy rw_pol_replace_csp "HTTP.RES.HEADER(\"Content-Security-Policy\").EXISTS" rw_act_replace_csp

bind vpn vserver vs_gateway -policy rw_pol_replace_csp -priority 100 -gotoPriorityExpression END -type RESPONSE

La condition .EXISTS garantit qu’on ne remplace que les réponses portant déjà un CSP (celui du firmware), sur la Gateway ciblée. Vous gardez le « secure by default » partout ailleurs.

Configuration de la Rewrite Policy CSP sur NetScaler Gateway Configuration de la Rewrite Action CSP sur NetScaler Gateway

Alternative — Désactiver le CSP global puis réinjecter

Si vous préférez désactiver globalement et repartir d’un insert, désactivez d’abord le header par défaut, puis construisez votre CSP selon votre IDP.

NetScaler CLIDésactivation globale
set aaa parameter -defaultCSPHeader DISABLE
save config

Domaines à whitelister selon les cas courants : Azure AD / Entra ID (login.microsoftonline.com, login.microsoft.com, aadcdn.msftauth.net, aadcdn.msauth.net) ; ADFS on-prem (FQDN de votre serveur ADFS) ; DUO (*.duosecurity.com, *.duofederal.com) ; reCAPTCHA (www.google.com/recaptcha, www.gstatic.com/recaptcha).

NetScaler CLIAction insert — exemple Azure AD + DUO
add rewrite action rw_act_csp_gateway insert_http_header Content-Security-Policy "\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://aadcdn.msftauth.net https://aadcdn.msauth.net https://*.duosecurity.com; style-src 'self' 'unsafe-inline' https://aadcdn.msftauth.net; img-src 'self' data: https: http://localhost:*; font-src 'self' data:; connect-src 'self' https://login.microsoftonline.com https://login.microsoft.com https://*.duosecurity.com; frame-src 'self' https://login.microsoftonline.com https://*.duosecurity.com receiver: citrixng: com.citrix.agmacepa: com.citrix.nsgclient: nsgcepa: application:; frame-ancestors 'self'; form-action 'self' https://login.microsoftonline.com https://login.microsoft.com; object-src 'none'; base-uri 'self'; report-uri /nscsp_violation/report_uri\""

Puis la policy (ciblant les réponses HTML générées par la Gateway, et évitant les doublons) et le bind :

NetScaler CLIPolicy insert + bind
add rewrite policy rw_pol_csp_gateway "HTTP.RES.HEADER(\"Content-Type\").CONTAINS(\"text/html\") && HTTP.RES.HEADER(\"Content-Security-Policy\").EXISTS.NOT" rw_act_csp_gateway

bind vpn vserver vs_gateway -policy rw_pol_csp_gateway -priority 100 -gotoPriorityExpression END -type RESPONSE

Approche progressive : Report-Only

Avant d’appliquer en mode bloquant, vous pouvez déployer la politique en Report-Only pour identifier les ressources manquantes, analyser les violations (ADM / console navigateur) quelques jours, ajuster la whitelist, puis basculer.

NetScaler CLIReport-Only
add rewrite action rw_act_csp_gw_reportonly insert_http_header Content-Security-Policy-Report-Only "\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://aadcdn.msftauth.net https://*.duosecurity.com; form-action 'self' https://login.microsoftonline.com; report-uri /nscsp_violation/report_uri\""

Étape de validation

  1. Connectez-vous à la Gateway, ouvrez les DevTools (F12).
  2. Onglet Network → requête de la page de login → vérifiez le header Content-Security-Policy dans les Response Headers.
  3. Onglet Console → vérifiez l’absence de violations CSP (messages en rouge).
  4. Testez l’authentification SAML complète (redirection IDP → callback → portail), et l’iframe DUO si applicable.
🔐
Et les hashes CSP pour éliminer unsafe-inline ?

Possible sur le papier (remplacer 'unsafe-inline' par les hashes SHA-256 des scripts inline de la page de login), mais : non documenté par Citrix, fortement couplé à la version de firmware (toute MAJ peut invalider un hash et casser la page de login), pas de génération dynamique côté NetScaler, et nFactor / login schemas multiplient les hashes à maintenir. À réserver aux exigences absolues (banque, défense). Pour la majorité des déploiements, le compromis 'unsafe-inline' avec une CSP bien construite par ailleurs reste le meilleur ratio sécurité/maintenabilité — à documenter en réponse aux pentests comme contrainte produit.

8. Valider avec le CSP Evaluator

Une fois la politique en place, collez-la dans le CSP Evaluator de Google — d’abord la CSP par défaut, puis votre version durcie — pour voir, directive par directive, ce que chacune apporte et ce qu’elle laisse ouvert.

CSP Evaluator (Google) - resultat sur la gateway avec la CSP par defaut CSP Evaluator (Google) - resultat sur la gateway durcie apres remplacement

Ce que l’évaluateur va signaler (et pourquoi c’est normal sur une Gateway)

Attendez-vous à des alertes sur 'unsafe-inline' et 'unsafe-eval' dans script-src. Elles affaiblissent réellement le CSP (elles ré-autorisent les scripts inline et l’exécution de chaînes via eval()), mais le portail de logon Gateway/StoreFront et l’intégration reCAPTCHA en ont besoin — c’est précisément pour ça que la politique par défaut de Citrix les inclut. Les retirer casse la page de login, sauf à passer à un CSP 100 % nonce/hash.

Les alertes plus douces sur les hôtes en allowlist et 'self' (« make sure this URL doesn’t serve JSONP / Angular ») sont des mises en garde, pas des erreurs : un hôte autorisé ne devient un vecteur de contournement que s’il héberge un endpoint JSONP, une lib AngularJS, ou des fichiers uploadés servis en JS. Les URLs reCAPTCHA sont scopées au chemin (bien), et votre propre domaine est maîtrisé.

🎯
Pas de score A+ sur une Gateway — et c’est attendu

Verrouillez tout le reste (object-src 'none', form-action 'self', frame-src/child-src scopés, report-uri pour la télémétrie) et assumez unsafe-inline/unsafe-eval comme un compromis produit documenté — utile à mentionner en réponse aux rapports de pentest.

9. Cas pratique : ajouter un CSP sur une application legacy

Votre application RH interne n’envoie aucun header CSP. Voici comment en injecter un via NetScaler.

NetScaler CLIAction + policy + bind (LB vServer)
add rewrite action rw_act_csp_hrapp insert_http_header Content-Security-Policy "\"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'; form-action 'self'; object-src 'none'; base-uri 'self'\""

# Conditionnel : n'injecte que si le backend n'envoie pas déjà un CSP
add rewrite policy rw_pol_csp_hrapp "HTTP.REQ.URL.PATH.STARTSWITH(\"/hrapp\") && HTTP.RES.HEADER(\"Content-Security-Policy\").EXISTS.NOT" rw_act_csp_hrapp

bind lb vserver vs_hrapp -policyName rw_pol_csp_hrapp -priority 100 -gotoPriorityExpression END -type RESPONSE

Vérifiez ensuite via DevTools (F12) → Network → la requête → présence du header dans les Response Headers, Console pour les violations.

10. Bonnes pratiques

✅ Recommandations

Garder la CSP par défaut, remplacer à la demandePlutôt que désactiver globalement : replace conditionnel par Gateway.
Ne jamais superposer deux CSP sans le vouloirLe navigateur applique l’intersection la plus restrictive. Utilisez .EXISTS / .EXISTS.NOT.
Report-Only d’abord si vous repartez de zéroObserver les violations sans rien bloquer, ajuster, puis basculer.
Minimiser unsafe-inline / unsafe-evalSouvent imposés par les composants Citrix natifs — à documenter.
frame-ancestors plutôt que X-Frame-OptionsPlus flexible pour la protection clickjacking.
Monitorer les violations + valider au CSP Evaluatorreport-uri natif + Citrix ADM ; évaluation avant/après.

Synthèse

La CSP d’une gateway Citrix typique est fonctionnelle mais imparfaite : unsafe-inline, unsafe-eval et des directives permissives sur les images réduisent la protection réelle contre les XSS. Ces compromis sont souvent inévitables compte tenu des composants Citrix natifs et du reCAPTCHA. Depuis l’activation par défaut (14.1-47.46 / 13.1-59.19), la bonne hygiène consiste à garder la défaut et la remplacer à la demande, par Gateway, puis à valider. Pour vos applications backend, NetScaler offre un point de contrôle centralisé via les Rewrite Policies : un quick win de sécurité significatif sur des dizaines d’applications sans en toucher le code.

Références

J

Jérôme Dellacasa — Elyleo

Consultant indépendant Citrix CVAD & NetScaler · Certifié Architecte Citrix

25 ans d’expérience terrain sur les infrastructures de virtualisation et d’accès distant. Spécialiste sécurisation NetScaler, performance Citrix CVAD et projets EUC/VDI. Cet article fait partie d’une série sécurité applicative NetScaler (voir aussi : NetScaler 14.1, TLS 1.3, Password Spraying).

📅 Sécurisons votre NetScaler →

1 réflexion sur “Gestion des CSP Headers sur Citrix NetScaler”

  1. Ping : Elyleo

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Retour en haut