Règle
Éviter la récursivité sans profondeur protection.
La récursivité sans propre limitation de profondeur limitant risque pile
débordement et crée vulnérabilités vulnérabilités à partir de malveillante
entrées. Récursivité avec profondeur limites de profondeur limites et limites
limites et est acceptable.
Prise en charge linguistique : 45+Introduction
Les fonctions récursives sans limites de profondeur peuvent épuiser la pile d'appels (call stack), provoquant des plantages. Des entrées malveillantes, comme des objets JSON profondément imbriqués ou des structures de données cycliques, peuvent déclencher intentionnellement une récursion illimitée. Une seule requête spécialement conçue peut faire planter votre service en dépassant les limites de la pile, créant ainsi une vulnérabilité de déni de service triviale à exploiter.
Pourquoi c'est important
Implications de sécurité (attaques DoS) : Les attaquants peuvent élaborer des entrées qui déclenchent une récursion profonde, provoquant le crash de votre application. Les structures de données JSON, XML ou liées profondément imbriquées sont des vecteurs d'attaque courants. Une seule requête malveillante épuise la pile, rendant l'ensemble du service indisponible pour tous les utilisateurs.
Stabilité du système : Les erreurs de débordement de pile (stack overflow) font planter le processus immédiatement sans dégradation progressive. En production, cela signifie des requêtes abandonnées, des transactions interrompues et une indisponibilité du service. La récupération nécessite le redémarrage de toute l'application.
Épuisement des ressources : Une récursion non bornée consomme la mémoire de la pile de manière exponentielle. Chaque appel récursif ajoute une trame de pile, et les chaînes de récursion profondes peuvent consommer des mégaoctets de mémoire. Cela affecte d'autres processus sur le même serveur et peut déclencher des conditions de manque de mémoire.
Exemples de code
❌ Non conforme :
function processNestedData(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
const result = {};
for (const key in obj) {
result[key] = processNestedData(obj[key]);
}
return result;
}Pourquoi c'est incorrect : L'absence de limite de profondeur permet aux attaquants d'envoyer des objets profondément imbriqués qui dépassent les limites de la pile. Une entrée comme {a: {a: {a: {...}}}} imbriquée sur 10 000 niveaux de profondeur fait planter l'application avec un débordement de pile (stack overflow). La fonction récurse aveuglément sans vérifier la profondeur.
✅ Conforme :
function processNestedData(obj, depth = 0, maxDepth = 100) {
if (depth > maxDepth) {
throw new Error('Maximum nesting depth exceeded');
}
if (typeof obj !== 'object' || obj === null) {
return obj;
}
const result = {};
for (const key in obj) {
result[key] = processNestedData(obj[key], depth + 1, maxDepth);
}
return result;
}Pourquoi c'est important : Le maxDepth le paramètre limite la récursion à 100 niveaux, prévenant ainsi le débordement de pile (stack overflow). Cette limite est suffisamment élevée pour les structures de données imbriquées légitimes (la plupart des données réelles dépassent rarement 10 à 20 niveaux) tout en étant suffisamment basse pour arrêter les attaques avant qu'elles ne consomment une mémoire de pile significative. Une entrée malveillante profondément imbriquée génère une erreur au lieu de faire planter l'application. La vérification de la profondeur a lieu avant le traitement, ce qui permet une défaillance rapide lorsque les limites sont dépassées.
Conclusion
Ajoutez des paramètres de profondeur à toutes les fonctions récursives qui traitent des données externes. Définissez des profondeurs maximales raisonnables basées sur la complexité attendue de la structure de données. Lancez des erreurs ou renvoyez des valeurs par défaut lorsque les limites de profondeur sont dépassées, au lieu de provoquer un crash.
.avif)
