
Résoudre le blocage WAF d'Optimizely CMS 11 avec l'encodage Base64
Votre éditeur de contenu clique sur enregistrer. La page affiche une erreur. Encore un blocage WAF.
Ce scénario frustrant se répète quotidiennement pour les équipes qui utilisent Optimizely CMS 11 derrière un pare-feu d'application Web. Le blocage WAF d'Optimizely CMS 11 est l'un des problèmes les plus fréquents que nous rencontrons avec les déploiements en entreprise. L'éditeur essayait simplement d'ajouter un script de suivi ou d'intégrer du HTML, mais le WAF l'a identifié comme une potentielle attaque XSS et a bloqué la requête.
Ce guide explique pourquoi cela se produit, comment implémenter une solution de contournement avec l'encodage Base64, et quand vous devriez plutôt envisager des approches alternatives.
Ce que ce guide couvre
Nous allons explorer les raisons techniques derrière le blocage WAF dans les environnements CMS, puis construire un type de propriété personnalisé qui encode le contenu avant la soumission. Vous obtiendrez des exemples de code fonctionnels pour les composants côté serveur et côté client. Nous discuterons également quand cette approche est appropriée versus quand vous devriez plutôt demander des ajustements aux règles WAF. Ce tutoriel vous montrera comment contourner le blocage WAF que les éditeurs d'Optimizely CMS rencontrent quotidiennement.
Prérequis
Avant d'implémenter cette solution de contournement, vous aurez besoin de :
- Optimizely CMS 11 fonctionnant sur .NET Framework 4.7.x
- Une compréhension des types de propriétés personnalisés dans Optimizely
- Un accès pour modifier le code source de votre projet
- Une familiarité de base avec l'interface d'édition basée sur Dojo
- La permission de déployer des modifications (évidemment)
Ce guide couvre en détail le développement de types de propriétés personnalisés pour Optimizely CMS. Vous devriez également avoir une idée claire de quel WAF bloque vos requêtes. Les coupables habituels incluent Azure Application Gateway, AWS WAF, Cloudflare et les configurations basées sur ModSecurity.
Pourquoi les WAF bloquent votre contenu CMS
Le blocage CMS par les pare-feu d'application Web se produit parce que les WAF inspectent le trafic HTTP et bloquent les requêtes qui correspondent à des signatures d'attaque. Le problème? Le contenu CMS légitime contient souvent les mêmes patterns que les vraies attaques. Les faux positifs WAF déclenchés par le contenu CMS sont extrêmement courants dans les flux de travail éditoriaux.
Quand votre éditeur enregistre du contenu contenant des balises <script>, des gestionnaires d'événements comme onclick, ou des exemples de code intégrés, le WAF détecte des patterns qui ressemblent à des attaques XSS. La syntaxe de type SQL dans le contenu déclenche les règles de détection d'injection. Même les images encodées en Base64 peuvent lever des alertes parce que beaucoup de WAF décodent automatiquement le Base64 et analysent le résultat.
Les règles couramment déclenchées incluent :
- Rule 941100 : Attaque XSS détectée via libinjection
- Rule 941110 : Filtre XSS Catégorie 1
- Rule 942100 : Attaque par injection SQL détectée via libinjection
- Rule 949110 : Score d'anomalie entrant dépassé
Trouver la bonne solution au blocage XSS d'Optimizely CMS 11 dépend des règles spécifiques qui se déclenchent. En travaillant avec diverses entreprises, nous avons appris que les équipes marketing qui intègrent des codes de suivi tiers causent le plus de friction avec le WAF. Ils ajoutent des fonctionnalités commerciales légitimes, mais le WAF ne peut pas distinguer leur snippet Google Tag Manager d'une injection de script malveillant.
L'approche par encodage Base64
La solution de contournement est simple dans son concept : encoder le contenu en Base64 avant qu'il ne quitte le navigateur, puis le décoder quand il arrive au serveur. Puisque le corps de la requête HTTP contient du contenu encodé au lieu de HTML brut ou de balises script, la correspondance de patterns du WAF ne trouve rien de suspect. Le contournement WAF par encodage Base64 est une technique éprouvée pour gérer ces scénarios.
Voici comment les pièces s'assemblent :
- Un widget Dojo personnalisé encode le contenu avant la soumission du formulaire
- Les données encodées traversent le WAF sans déclencher de règles
- Un type de propriété personnalisé côté serveur décode vers le contenu original
- Le contenu est stocké normalement dans la base de données
- Les éditeurs ne voient jamais le processus d'encodage
Implémentation étape par étape
Étape 1 : Créer la classe de propriété personnalisée
Commencez par une propriété personnalisée qui gère le décodage Base64. Celle-ci étend le PropertyXhtmlString standard pour intercepter les valeurs lors de leur définition et récupération. Cette implémentation personnalisée de PropertyXhtmlString gère toute la logique d'encodage de manière transparente.
using System;
using System.Text;
using EPiServer.Core;
using EPiServer.PlugIn;
namespace YourProject.Properties
{
[PropertyDefinitionTypePlugIn]
public class EncodedXhtmlStringProperty : PropertyXhtmlString
{
public override object Value
{
get => base.Value;
set => base.Value = DecodeIfNeeded(value);
}
private object DecodeIfNeeded(object value)
{
if (value is string stringValue && IsBase64Encoded(stringValue))
{
try
{
var bytes = Convert.FromBase64String(stringValue);
return Encoding.UTF8.GetString(bytes);
}
catch (FormatException)
{
return value;
}
}
return value;
}
private bool IsBase64Encoded(string value)
{
if (string.IsNullOrEmpty(value))
return false;
// Check for Base64 marker prefix you'll add client-side
return value.StartsWith("B64:");
}
}
}Notez la vérification du préfixe B64:. Ajouter un marqueur à votre contenu encodé rend la détection fiable sans décoder accidentellement du contenu qui se trouve être du Base64 valide.
Étape 2 : Construire le descripteur d'éditeur
Le descripteur d'éditeur indique à Optimizely d'utiliser votre éditeur JavaScript personnalisé pour ce type de propriété. Ce tutoriel sur le descripteur d'éditeur Optimizely couvre la configuration essentielle requise.
using System;
using System.Collections.Generic;
using EPiServer.Cms.Shell.UI.ObjectEditing.EditorDescriptors;
using EPiServer.Core;
using EPiServer.Shell.ObjectEditing;
using EPiServer.Shell.ObjectEditing.EditorDescriptors;
namespace YourProject.EditorDescriptors
{
[EditorDescriptorRegistration(
TargetType = typeof(XhtmlString),
UIHint = "EncodedXhtml")]
public class EncodedXhtmlEditorDescriptor : XhtmlStringEditorDescriptor
{
public override void ModifyMetadata(
ExtendedMetadata metadata,
IEnumerable<Attribute> attributes)
{
base.ModifyMetadata(metadata, attributes);
metadata.ClientEditingClass = "yourproject/editors/EncodedXhtmlEditor";
}
}
}La configuration du descripteur d'éditeur XhtmlString ci-dessus connecte votre propriété personnalisée au composant côté client.
Étape 3 : Créer l'éditeur côté client
Ce widget Dojo enveloppe l'éditeur XHTML standard et intercepte la valeur avant la soumission. Le widget Dojo qu'utilise Optimizely CMS 11 suit le pattern de module AMD.
Créez ce fichier à l'emplacement /ClientResources/Scripts/editors/EncodedXhtmlEditor.js :
define([
"dojo/_base/declare",
"dojo/_base/lang",
"epi-cms/contentediting/editors/XhtmlStringEditor"
], function (declare, lang, XhtmlStringEditor) {
return declare([XhtmlStringEditor], {
_setValueAttr: function (value) {
// Decode for display if it's encoded
if (value && typeof value === "string" && value.indexOf("B64:") === 0) {
try {
var encoded = value.substring(4);
value = decodeURIComponent(escape(atob(encoded)));
} catch (e) {
console.warn("Failed to decode Base64 value", e);
}
}
this.inherited(arguments, [value]);
},
_getValueAttr: function () {
var value = this.inherited(arguments);
if (value && typeof value === "string" && value.length > 0) {
try {
var encoded = btoa(unescape(encodeURIComponent(value)));
return "B64:" encoded;
} catch (e) {
console.warn("Failed to encode value to Base64", e);
return value;
}
}
return value;
}
});
});Étape 4 : Enregistrer les ressources client
Ajoutez le chemin du module à votre module.config :
<module>
<dojo>
<paths>
<add name="yourproject" path="Scripts" />
</paths>
</dojo>
</module>Étape 5 : Appliquer le UIHint à vos propriétés
Utilisez maintenant l'éditeur personnalisé sur toute propriété qui nécessite un contournement WAF :
public class ArticlePage : PageData
{
[UIHint("EncodedXhtml")]
[Display(Name = "Body Content")]
public virtual XhtmlString MainBody { get; set; }
[UIHint("EncodedXhtml")]
[Display(Name = "Tracking Scripts")]
public virtual XhtmlString TrackingCode { get; set; }
}Notre équipe a constaté que l'appliquer de façon sélective fonctionne mieux que de l'activer globalement. Utilisez-le uniquement sur les propriétés où les éditeurs rencontrent régulièrement des blocages WAF.
Gérer les propriétés de chaîne de caractères simples
Parfois, vous devez encoder des chaînes de caractères simples plutôt que du contenu XHTML. L'approche est similaire mais plus simple :
[BackingType(typeof(PropertyLongString))]
public class EncodedStringProperty : PropertyLongString
{
public override object Value
{
get => DecodeValue(base.Value);
set => base.Value = value;
}
private object DecodeValue(object value)
{
if (value is string str && str.StartsWith("B64:"))
{
try
{
var encoded = str.Substring(4);
var bytes = Convert.FromBase64String(encoded);
return Encoding.UTF8.GetString(bytes);
}
catch
{
return value;
}
}
return value;
}
}Utilisez ceci pour les jetons JWT, le JSON sérialisé, ou d'autres données textuelles qui déclenchent les règles WAF.
Erreurs courantes à éviter
Oublier le préfixe marqueur. Sans un indicateur clair comme B64:, votre décodeur pourrait essayer de décoder du contenu qui était déjà en texte brut mais qui ressemblait à du Base64 valide. Cela corrompt les données silencieusement.
Encoder côté serveur au lieu du client. Si vous encodez dans le code côté serveur avant la réponse HTTP, vous n'avez rien résolu. Le WAF inspecte la requête provenant du navigateur, pas la réponse qui y retourne. L'encodage doit se faire en JavaScript avant la soumission du formulaire.
Appliquer à toutes les propriétés aveuglément. La surcharge d'encodage supplémentaire sur chaque propriété ralentit l'expérience d'édition. Appliquez le UIHint seulement là où c'est nécessaire.
Ne pas gérer les échecs de décodage gracieusement. Le contenu migré d'avant votre implémentation n'aura pas le préfixe. Assurez-vous que votre décodeur retourne la valeur originale par défaut quand le décodage échoue.
Sauter la conversation sur la sécurité. Cette solution de contournement existe parce que le WAF fait son travail. Avant d'implémenter, parlez avec votre équipe de sécurité. Ils préféreront peut-être ajuster les règles WAF plutôt que de les contourner.
Tests et vérification
Vérifier que l'encodage fonctionne
- Ouvrez les outils de développement du navigateur
- Naviguez vers une page avec votre propriété encodée
- Modifiez le contenu et ajoutez du HTML qui déclenchait des blocages auparavant (comme une balise <script>)
- Surveillez l'onglet Réseau quand vous enregistrez
- Confirmez que le corps de la requête affiche B64: suivi du contenu encodé
- Vérifiez que l'enregistrement se termine sans erreurs WAF
Vérifier que le décodage fonctionne
- Enregistrez du contenu avec la propriété encodée
- Interrogez la base de données directement et confirmez que la valeur stockée est décodée (pas en Base64)
- Rechargez la page en mode édition et confirmez que le contenu s'affiche correctement
- Vérifiez le site publié pour vous assurer que le contenu s'affiche correctement
Tester les cas limites
- Contenu vide
- Contenu très long (des mégaoctets de texte)
- Contenu avec des caractères Unicode
- Contenu avec des données Base64 existantes (comme des images intégrées)
- Contenu existant créé avant cette implémentation
Quand utiliser cette approche (et quand ne pas le faire)
Cette solution de contournement par encodage a du sens quand :
- Votre équipe de sécurité ne veut pas ou ne peut pas modifier les règles WAF
- Vous avez besoin d'une solution rapide pendant que l'ajustement des règles est négocié
- Des propriétés spécifiques déclenchent constamment des faux positifs
- Vous travaillez avec un WAF géré que vous ne contrôlez pas
Nous déconseillons cette approche quand :
- Vous pouvez configurer des exclusions de règles WAF pour les chemins CMS
- Votre environnement exige une conformité stricte (PCI, SOC2, ISO)
- Vous avez l'accès pour mettre en liste blanche les plages IP des éditeurs
- Vous planifiez de migrer vers CMS 12 bientôt de toute façon
La meilleure solution à long terme est habituellement la configuration du WAF. Les exclusions basées sur les chemins pour /episerver/ ou /EPiServer/CMS/Content/, combinées avec des restrictions IP pour les éditeurs, résolvent le problème sans code personnalisé. La configuration Azure WAF pour Optimizely et les exceptions de règles ModSecurity pour CMS sont deux chemins viables selon votre infrastructure.
Implications de sécurité
Cette approche réduit effectivement la défense en profondeur. Les WAF fournissent une couche de protection même pour les utilisateurs authentifiés, et contourner cette couche signifie que tout contenu malveillant qu'un utilisateur authentifié soumet ne sera pas intercepté.
Pour la plupart des équipes, ce compromis est acceptable parce que :
- Le mode édition requiert déjà une authentification
- Les éditeurs sont des utilisateurs internes de confiance
- Le contenu est révisé avant publication
Documentez votre implémentation et incluez-la dans les revues de sécurité. Journalisez toutes les soumissions de contenu pour avoir une piste d'audit. Et continuez à pousser votre équipe de sécurité pour des ajustements appropriés des règles WAF comme solution permanente.
Regard vers l'avenir : Migration CMS 12
Optimizely CMS 11 est maintenant considéré comme un produit en fin de vie, avec le support standard se terminant fin 2024. CMS 12 fonctionne sur .NET 6 et a une architecture différente qui pourrait gérer les interactions WAF différemment. Les considérations WAF pour la migration vers Optimizely CMS 12 devraient faire partie de votre planification de mise à niveau.
Si vous planifiez une migration de toute façon, vous pourriez sauter l'implémentation de cette solution de contournement et concentrer cet effort sur la mise à niveau à la place. Les problèmes WAF pourraient se résoudre d'eux-mêmes avec la nouvelle plateforme, ou au minimum vous voudrez réévaluer votre approche avec la nouvelle architecture.
En conclusion
Le blocage WAF dans Optimizely CMS 11 est un vrai problème qui perturbe les flux de travail des éditeurs. L'approche par encodage Base64 vous donne une solution fonctionnelle en encodant le contenu avant qu'il n'atteigne le WAF et en le décodant côté serveur.
L'implémentation implique un type de propriété personnalisé, un descripteur d'éditeur, et un widget Dojo côté client. Appliquez-le de façon sélective aux propriétés qui déclenchent des faux positifs, pas globalement. Testez minutieusement, particulièrement les cas limites autour du contenu existant et de l'Unicode.
Rappelez-vous que c'est une solution de contournement, pas une solution permanente. Continuez à pousser pour des exclusions de règles WAF appropriées qui reconnaissent les patterns de trafic CMS.
Si votre équipe fait face à des frictions WAF dans Optimizely ou envisage une migration vers CMS 12, nous pouvons vous aider à évaluer la bonne approche pour votre environnement spécifique et vos exigences de sécurité. Contactez-nous pour discuter de votre situation.
