Aller au contenu

Modèle de menaces du moteur

Cette page décrit le modèle de menaces du moteur principal NextPDF. Elle énumère les classes d’attaque que le moteur considère comme relevant de son périmètre lorsqu’il traite une entrée influencée par un attaquant (HTML, CSS, SVG, polices, images et PDF existants). Elle indique la posture par défaut de chaque capacité d’accès à une ressource externe. Elle renvoie au garde-fou intégré au code qui atténue chaque classe.

Limite. Un modèle de menaces documente les menaces prises en compte et les mesures d’atténuation qui leur sont associées. Il n’affirme pas l’absence de vulnérabilités. Une classe absente de cette liste n’est donc pas prouvée inexistante : elle peut simplement se trouver hors du périmètre actuel du modèle. Les fonctionnalités non implémentées sont soumises à une revue formelle de menace avant leur livraison. Considère cette page comme le compte rendu d’une conception délibérée, et non comme une preuve de sécurité.

Fenêtre de terminal
composer require nextpdf/core:^3

Les garde-fous décrits ici font partie du paquet principal ; aucune dépendance supplémentaire n’est nécessaire pour les activer. Ils le sont par défaut.

Le modèle suit la structure recommandée par le processus de modélisation des menaces de l’OWASP (owasp_threat_modeling#x1.x11.p6) : décomposer le système autour des points où une entrée non fiable franchit une limite de confiance, énumérer les menaces à chaque limite et consigner la mesure d’atténuation.

La principale limite de confiance du moteur est l’ingestion de documents : tout point où un contenu rédigé ailleurs — une feuille de style distante, une source @font-face, un <image href>, une facture XML embarquée, un PDF à inspecter — pourrait amener le moteur à récupérer, analyser ou décompresser quelque chose. Le principe directeur est le refus par défaut : chaque capacité d’accès à une ressource externe est DÉSACTIVÉE tant que l’appelant ne l’active pas explicitement au moyen d’un objet de politique. C’est le principe de moindre fonctionnalité de NIST SP 800-53 Rev. 5 CM-7 (nist_sp_800_53r5#x4.x182.p14) appliqué à un moteur de rendu : la posture la plus stricte est la valeur par défaut du constructeur. Ouvrir une capacité est une décision explicite de l’appelant.

Le modèle de menaces n’est pas lui-même une API. Les objets de politique qui l’expriment sont documentés sur les pages de modules ; les points d’entrée pertinents du point de vue de la confiance sont le contrat de politique d’accès aux ressources externes (ExternalResourcePolicyInterface, avec DefaultExternalResourcePolicy comme politique par défaut de refus total) ainsi que les garde-fous d’URL et de XML (UrlValidator, XmlGuard). Cette page renvoie à leur comportement ; elle ne documente pas à nouveau leurs signatures.

La posture sécurisée est la valeur par défaut. Aucun code n’est requis pour l’obtenir :

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Html\DefaultExternalResourcePolicy;
// Out of the box: @font-face blocked, @import blocked, background-image
// blocked, SVG external refs blocked. A document that tries to fetch a
// remote resource gets a system-font fallback or an ignored rule — not an
// outbound request.
$policy = new DefaultExternalResourcePolicy();

Ouvrir une capacité est délibéré et étroitement délimité. En production, un appelant qui doit autoriser une police Web hébergée sur un CDN via HTTPS l’active explicitement et en restreint la portée :

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Html\DefaultExternalResourcePolicy;
// Explicit, scoped opt-in. The HTTPS scheme is required; size and glyph
// caps still apply; the URL still passes the SSRF guard before any fetch.
$policy = (new DefaultExternalResourcePolicy())
->withFontFaceAllowed(['https']);
  • Non implémenté ne signifie pas sûr par accident. Des capacités comme background-image url() en CSS ne sont pas implémentées. Elles ne présentent donc aucune surface d’attaque actuelle. Mais elles sont documentées comme devant faire l’objet d’une revue formelle de menace avant toute implémentation future. L’absence de code est la mesure d’atténuation aujourd’hui, pas une garantie permanente.
  • Le DNS rebinding est une cible mouvante. UrlValidator résout le nom d’hôte et renvoie l’IP résolue afin que l’appelant puisse épingler la connexion (CURLOPT_RESOLVE), ce qui referme la fenêtre TOCTOU entre la validation et la récupération. C’est une défense de type best effort, pas une défense absolue. Un opérateur derrière un proxy de sortie permissif peut tout de même atteindre des hôtes internes que la bibliothèque ne voit pas.
  • Les bits de permission ne sont pas un contrôle d’accès. Un document qui « bloque la copie » s’appuie sur la coopération du lecteur, pas sur une application réelle. Ce point est traité dans le modèle de sécurité. On le signale ici parce que c’est une idée fausse fréquente sur les modèles de menaces.

Les garde-fous sont conçus pour échouer rapidement et borner le travail : le garde-fou XML rejette le DOCTYPE avant l’analyse et plafonne la taille d’entrée ; le chemin de traitement des images impose un plafond en mégapixels et en octets avant la décompression ; le garde-fou d’URL rejette selon le scheme/host avant l’ouverture de tout socket. Le coût de la valeur par défaut sécurisée est une requête rejetée, et non une requête lente.

Les classes d’attaque considérées et leurs mesures d’atténuation intégrées au code :

Classe de menace (CWE / OWASP)Vecteur dans un moteur PDFGarde-fou intégré au code
SSRF (OWASP Top 10 2025 ; owasp_top10_2025#x3.x1.p26)@font-face/@import/url() qui pointent vers 169.254.169.254 ou un hôte interne ; récupérateurs TSA/OCSP/CRLUrlValidator::validateExternalUrl() bloque les plages private/reserved/loopback/link-local et les points de terminaison de métadonnées cloud, rejette les schemes dangereux, résout le DNS et renvoie l’IP pour l’épinglage de connexion
XXE (cwe_top25_2025#x28.x2.p42)Entités externes / DOCTYPE dans une facture XML embarquée ou un paquet XMPXmlGuard::loadXml() impose LIBXML_NONET et rejette d’emblée toute déclaration DOCTYPE, ainsi que les caractères de contrôle interdits par XML 1.0 et un plafond de taille d’entrée
Bombe de décompressionImage 1×1 masquant une charge utile de 100 MP ; WOFF2 surdimensionnéLe chemin de traitement des images impose un plafond en mégapixels et un plafond en octets avant la décompression ; le chemin de traitement des polices plafonne la taille de fichier et le nombre de glyphes
Traversée de cheminfile:///etc/passwd via une police ou un SVG srcRessources externes en refus total par défaut ; les chemins de fichiers locaux sont résolus via realpath() par rapport à une liste d’autorisation de répertoires lorsqu’ils sont explicitement activés
Injection de contenuChaîne fabriquée s’échappant d’un opérateur PDF ; data:/javascript: hrefÉchappement des chaînes PDF à l’émission ; liste d’autorisation de schemes + assainissement des href sur les annotations

Les valeurs par défaut se résument à une posture de refus total d’accès aux ressources externes : les polices, @import, les images de fond et les références externes SVG sont désactivés tant que l’appelant n’y consent pas explicitement par scheme, conformément à la matrice de couverture des propriétés de sécurité maintenue aux côtés du code.

Cette page documente les menaces considérées. Ce n’est pas un rapport de test d’intrusion et elle n’affirme pas que les mesures d’atténuation listées sont complètes, ni qu’aucune autre classe de faiblesse ne s’applique.

Ce n’est pas un profil de conformité. Le modèle de menaces s’inspire du processus de modélisation des menaces de l’OWASP et de la taxonomie des faiblesses CWE Top 25 (cwe_top25_2025#x28.x2.p42) ; il ne revendique aucune conformité à un quelconque schéma de certification de sécurité. Une évaluation indépendante relève d’un audit, pas de ce document.