Erreur 403 sur hébergement mutualisé OVH (ModSecurity)
Bug: Erreur 403 sur hébergement mutualisé OVH (ModSecurity)
Description du problème
Sur un hébergement mutualisé OVH avec ModSecurity activé, toutes les requêtes AJAX échouent avec une erreur HTTP 403 Forbidden lors de :
- L'ajout de risques
- L'ajout de tâches
- L'ajout d'évaluations
- L'enregistrement de métadonnées (après upload d'images)
Cause
Le pare-feu applicatif ModSecurity bloque les requêtes POST avec Content-Type: text/plain, qui est automatiquement généré par jQuery lorsque :
- contentType: false est utilisé
- AVEC data: JSON.stringify(...)
Log ModSecurity :
[id "960010"] [msg "Request content type is not allowed by policy"] [data "text/plain"]
Fichiers concernés
Digirisk :
- js/modules/risk.js (lignes 188, 271, 322)
- js/modules/task.js (7 occurrences)
- js/modules/riskAssessment.js (3 occurrences)
Saturne :
- js/modules/mediaGallery.js (lignes 146, 238, 309, 596, 611, 679, 717, 751, 785)
- js/modules/utils.js
- js/modules/audio.js
- js/modules/dashboard.js
- js/modules/dragable.js
Solution
Pour les requêtes qui envoient du JSON avec JSON.stringify() : ❌ Incorrect :
$.ajax({
data: JSON.stringify({...}),
processData: false,
contentType: false, // Génère "text/plain"
});
✅ Correct :
$.ajax({
data: JSON.stringify({...}),
processData: false,
contentType: 'application/json',
});
⚠️ Exception importante : Pour les uploads de fichiers avec FormData, garder contentType: false : $.ajax({
data: formData, // FormData object
processData: false,
contentType: false, // Correct pour multipart/form-data
});
Environnement
Dolibarr : 21.0.1 Digirisk : 21.1.0 Hébergement : OVH mutualisé Pro ModSecurity : Activé (règle CRS 960010)
Impact
- Ce bug rend Digirisk inutilisable (à partir de la saisie des risques, des tâches, l'upload de photos...) sur les hébergements mutualisés avec ModSecurity (OVH, certains autres hébergeurs).
Reproductibilité
- 100% sur hébergement OVH mutualisé avec ModSecurity activé.
- 0% sur serveur local (WAMP/MAMP) ou serveurs sans WAF.
Correction manuelle de ce bug
# Digirisk - Correction globale
cd digiriskdolibarr/
find js/modules/ -name "*.js" -exec sed -i 's/contentType: false,/contentType: '\''application\/json'\'',/g' {} \;
npx gulp js_backend
# Saturne - Correction avec exceptions
cd ../saturne/
find js/modules/ -name "*.js" ! -name "mediaGallery.js" -exec sed -i 's/contentType: false,/contentType: '\''application\/json'\'',/g' {} \;
# mediaGallery.js : correction globale puis exceptions
sed -i 's/contentType: false,/contentType: '\''application\/json'\'',/g' js/modules/mediaGallery.js
sed -i '309s/contentType: '\''application\/json'\'',/contentType: false,/' js/modules/mediaGallery.js
sed -i '596s/contentType: '\''application\/json'\'',/contentType: false,/' js/modules/mediaGallery.js
npx gulp js_backend
# Uploadez les fichiers .min.js générés sur votre serveur
- saturne.min.js
- digiriskdolibarr.min.js
Script de correction de ce bug
#!/bin/bash
# Script de correction du bug ModSecurity sur Digirisk/Saturne
# Auteur: Communauté Digirisk
# Date: Novembre 2025
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}Correction bug ModSecurity (HTTP 403)${NC}"
echo -e "${GREEN}========================================${NC}\n"
# Vérifier qu'on est au bon endroit
if [ ! -d "digiriskdolibarr" ] || [ ! -d "saturne" ]; then
echo -e "${RED}Erreur: Ce script doit être exécuté depuis le dossier parent contenant 'digiriskdolibarr' et 'saturne'${NC}"
exit 1
fi
# ==========================================
# PARTIE 1: Correction Digirisk
# ==========================================
echo -e "${YELLOW}[1/5] Correction des fichiers Digirisk...${NC}"
# Corriger tous les fichiers JS sauf ceux qui utilisent FormData
find digiriskdolibarr/js/modules/ -name "*.js" -type f | while read file; do
# Vérifier si le fichier contient contentType: false
if grep -q "contentType: false" "$file"; then
sed -i 's/contentType: false,/contentType: '\''application\/json'\'',/g' "$file"
echo " ✓ Corrigé: $file"
fi
done
# ==========================================
# PARTIE 2: Correction Saturne (avec précaution)
# ==========================================
echo -e "\n${YELLOW}[2/5] Correction des fichiers Saturne...${NC}"
# Fichiers Saturne - Correction générale
find saturne/js/modules/ -name "*.js" ! -name "mediaGallery.js" -type f | while read file; do
if grep -q "contentType: false" "$file"; then
sed -i 's/contentType: false,/contentType: '\''application\/json'\'',/g' "$file"
echo " ✓ Corrigé: $file"
fi
done
# Cas spécial: mediaGallery.js
echo -e "\n${YELLOW}[3/5] Correction spéciale de mediaGallery.js...${NC}"
MEDIA_GALLERY="saturne/js/modules/mediaGallery.js"
if [ -f "$MEDIA_GALLERY" ]; then
# Correction globale d'abord
sed -i 's/contentType: false,/contentType: '\''application\/json'\'',/g' "$MEDIA_GALLERY"
# Puis on remet contentType: false pour les vrais uploads de fichiers (lignes avec FormData)
# On cherche les lignes qui ont "data: formdata" et on remonte pour trouver contentType
# Ligne ~309 (premier upload)
sed -i '309s/contentType: '\''application\/json'\'',/contentType: false,/' "$MEDIA_GALLERY"
# Ligne ~596 (deuxième upload)
sed -i '596s/contentType: '\''application\/json'\'',/contentType: false,/' "$MEDIA_GALLERY"
echo " ✓ Corrigé: $MEDIA_GALLERY (avec exceptions FormData)"
else
echo -e " ${RED}✗ Fichier non trouvé: $MEDIA_GALLERY${NC}"
fi
# ==========================================
# PARTIE 3: Recompilation
# ==========================================
echo -e "\n${YELLOW}[4/5] Recompilation des fichiers JavaScript...${NC}"
# Recompiler Digirisk
echo " → Compilation de Digirisk..."
cd digiriskdolibarr
if [ -f "package.json" ]; then
npm install --silent > /dev/null 2>&1
npx gulp js_backend 2>&1 | grep -E "Finished|error" || true
echo " ✓ digiriskdolibarr.min.js généré"
else
echo -e " ${RED}✗ package.json non trouvé dans digiriskdolibarr${NC}"
fi
cd ..
# Recompiler Saturne
echo " → Compilation de Saturne..."
cd saturne
if [ -f "package.json" ]; then
npm install --silent > /dev/null 2>&1
npx gulp js_backend 2>&1 | grep -E "Finished|error" || true
echo " ✓ saturne.min.js généré"
else
echo -e " ${RED}✗ package.json non trouvé dans saturne${NC}"
fi
cd ..
# ==========================================
# PARTIE 4: Vérification
# ==========================================
echo -e "\n${YELLOW}[5/5] Vérification des corrections...${NC}"
# Compter les occurrences de application/json
DIGIRISK_COUNT=$(grep -ro "application/json" digiriskdolibarr/js/digiriskdolibarr.min.js 2>/dev/null | wc -l || echo "0")
SATURNE_COUNT=$(grep -ro "application/json" saturne/js/saturne.min.js 2>/dev/null | wc -l || echo "0")
echo " ✓ Digirisk: $DIGIRISK_COUNT occurrences de 'application/json'"
echo " ✓ Saturne: $SATURNE_COUNT occurrences de 'application/json'"
# ==========================================
# RÉSUMÉ
# ==========================================
echo -e "\n${GREEN}========================================${NC}"
echo -e "${GREEN}✓ Correction terminée avec succès !${NC}"
echo -e "${GREEN}========================================${NC}"
echo -e "\n${YELLOW}Prochaines étapes:${NC}"
echo "1. Uploadez les fichiers suivants sur votre serveur via FTP:"
echo " → htdocs/custom/digiriskdolibarr/js/digiriskdolibarr.min.js"
echo " → htdocs/custom/saturne/js/saturne.min.js"
echo ""
echo "2. Videz le cache de votre navigateur (Ctrl+Shift+Suppr)"
echo ""
echo "3. Testez les fonctionnalités suivantes:"
echo " ✓ Ajout de risques"
echo " ✓ Ajout de tâches"
echo " ✓ Ajout d'évaluations"
echo " ✓ Upload d'images"
echo ""
echo -e "${GREEN}Le bug ModSecurity devrait être résolu ! 🎉${NC}\n"
Utilisation du script
# 1. Téléchargez les modules sur votre machine locale
cd ~/Téléchargements/
mkdir digirisk-fix && cd digirisk-fix
# Téléchargez depuis votre serveur FTP ou GitHub:
# - digiriskdolibarr/
# - saturne/
# 2. Rendez le script exécutable
chmod +x fix-modsecurity-bug.sh
# 3. Exécutez le script
./fix-modsecurity-bug.sh
# 4. Uploadez les fichiers .min.js générés sur votre serveur
- saturne.min.js
- digiriskdolibarr.min.js
Environment Version
21.1.0
Environment OS
serveur linux
Environment Web server
lamp
Environment PHP
8.3
Environment Database
mysql 8.4
@phardouin mais c'est génial ça ! J'adore cette participation si tu m'envoi tes coordonnées on t'envoie un jeu de cartes sur la prévention ! Est-ce qu'on se voit au devcamp ? @phardouin