Contrats / Politique de sécurité
Le domaine security-policy regroupe trois contrats deny-by-default : CryptoPolicyInterface contrôle le choix des algorithmes et des clés, HtmlSecurityPolicyInterface restreint la surface des fonctionnalités HTML, et ExternalResourcePolicyInterface régit le chargement des ressources distantes. Chacun est un contrat : un déploiement peut donc fournir une politique plus stricte sans forker le code.
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »CryptoPolicyInterface est le point de contrôle cryptographique. Le cœur le consulte avant toute étape de signature, de chiffrement ou de hachage. La vérification couvre le hachage, l’OID de signature, le chiffrement et la robustesse de la clé. Le contrat indique aussi le hachage minimal et un nom de politique pour le journal d’audit. Il applique un jeu de règles tel que FIPS 140-3 ou eIDAS. Le code de signature et de chiffrement reste inchangé. Quand aucune politique n’est définie, tous les algorithmes sont autorisés. Un site soumis à une réglementation doit définir une politique explicite.
HtmlSecurityPolicyInterface agit au niveau de l’analyse HTML. Il s’exécute avant que le contenu n’atteigne le moindre moteur de rendu. Il indique si une balise, un attribut, une propriété CSS ou un schéma d’URL est autorisé. Il plafonne aussi la taille de l’entrée et la profondeur d’imbrication. Il se combine avec les politiques de transport propres à chaque moteur de rendu (Chrome, Cloudflare, Gotenberg), qui fixent des limites de taille et des en-têtes CSP. La politique HTML réduit la surface d’attaque de la couche d’analyse. Une balise supprimée n’atteint jamais la mise en page. Un élément injecté ne peut donc pas modifier la sortie. Quand aucune politique n’est définie, la valeur par défaut autorise l’ensemble des fonctionnalités.
ExternalResourcePolicyInterface indique si le pipeline HTML peut récupérer une police, une feuille de style ou une image externe. Il fixe aussi les limites applicables à chaque récupération. Sa posture par défaut est deny-all. Chaque option reste désactivée tant que tu ne l’actives pas. Le contrat applique le principe du moindre privilège. Du HTML non fiable peut pointer vers une URL contrôlée par un attaquant. Il contrôle la récupération @font-face par schéma, taille et nombre de glyphes. Il contrôle @import par schéma, profondeur et taille totale. Il contrôle background-image au moyen d’une liste de schémas et d’une liste blanche de domaines à correspondance exacte. Il plafonne la taille des data-URI. Il contrôle aussi les références externes des SVG. Le contrat précise qu’en production, elles doivent toujours être refusées. Elles ouvrent la voie à la falsification de requête et à l’injection de scripts. La récupération d’URL ouverte est un vecteur de falsification de requête côté serveur. Le contrôle d’accès est contourné en modifiant l’URL, conformément à l’OWASP Top 10 2025. Les composants doivent provenir uniquement de sources officielles, via des liens sécurisés.
Surface de l’API
Section intitulée « Surface de l’API »| Type | Nature | Membres clés | Stabilité | Depuis |
|---|---|---|---|---|
CryptoPolicyInterface | interface | isHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName() | stable | 1.9.0 |
HtmlSecurityPolicyInterface | interface | isTagAllowed(), isAttributeAllowed(), isCssPropertyAllowed(), isUrlSchemeAllowed(), getMaxInputSize(), getMaxNestingDepth(), getName() | stable | 3.1.0 |
ExternalResourcePolicyInterface | interface | isFontFaceAllowed(), getAllowedFontSchemes(), getMaxFontFileSize(), getMaxFontGlyphs(), isImportAllowed(), getMaxImportDepth(), isBackgroundImageAllowed(), getAllowedImageDomains(), getMaxDataUrlSize(), isSvgExternalReferenceAllowed() | stable | 4.0.0 |
ExternalResourcePolicyInterface renvoie des bornes typées : des tailles positive-int, une profondeur d’import int<1, 100>, ainsi que des listes de schémas et de domaines list<non-empty-string>. L’implémentation par défaut refuse toutes les capacités.
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\HtmlSecurityPolicyInterface;
/** * Decide whether a tag survives the policy. * * @param HtmlSecurityPolicyInterface $policy A core or custom policy. */function tagSurvives(HtmlSecurityPolicyInterface $policy, string $tag): bool{ return $policy->isTagAllowed($tag);}La fonction dépend du contrat. Une politique restrictive et la politique par défaut satisfont toutes deux ce contrat.
Exemple de code — Production
Section intitulée « Exemple de code — Production »<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;use NextPDF\Contracts\ExternalResourcePolicyInterface;use NextPDF\Contracts\HtmlSecurityPolicyInterface;use Psr\Log\LoggerInterface;
final readonly class UntrustedHtmlGate{ public function __construct( private HtmlSecurityPolicyInterface $htmlPolicy, private ExternalResourcePolicyInterface $resourcePolicy, private CryptoPolicyInterface $cryptoPolicy, private LoggerInterface $logger, ) {}
/** * Reject input that exceeds the configured limits before rendering. * * @param string $html Untrusted HTML markup. */ public function assertAcceptable(string $html): void { $maxInput = $this->htmlPolicy->getMaxInputSize();
if ($maxInput > 0 && \strlen($html) > $maxInput) { $this->logger->warning('HTML rejected: input over limit', [ 'policy' => $this->htmlPolicy->getName(), 'limit' => $maxInput, ]);
throw new \LengthException('HTML input exceeds policy limit.'); }
if ($this->resourcePolicy->isSvgExternalReferenceAllowed()) { $this->logger->error('Unsafe policy: SVG external references enabled.');
throw new \LogicException('SVG external references must be denied in production.'); } }}Le point de contrôle applique le plafond d’entrée et refuse une politique de ressources non sûre avant l’exécution du pipeline. Il journalise le nom de la politique pour l’audit et lève une exception spécifique.
Cas limites et pièges
Section intitulée « Cas limites et pièges »CryptoPolicyInterfaceautorise tous les algorithmes quand aucune politique n’est définie. Cette ouverture par défaut est un confort pour le développement, pas une posture de production. Définis une politique explicite dans tout déploiement soumis à une réglementation.HtmlSecurityPolicyInterface::getMaxInputSize()renvoie0pour une taille illimitée. Traite0comme « aucune limite de politique », pas comme « tout refuser », et applique aussi un plafond au niveau du transport.ExternalResourcePolicyInterfaceest deny-all par défaut. Activer@font-faceoubackground-imagesans définir de liste de schémas ouvre une surface de falsification de requête ; définis la liste blanche lorsque tu actives une capacité.- Une liste blanche de domaines vide sur
getAllowedImageDomains()signifie que tous les domaines sont autorisés dès que les images de fond sont activées. Une liste vide n’est pas un refus ; fournis des domaines explicites. isSvgExternalReferenceAllowed()doit renvoyerfalseen production. Le contrat le documente ; une politique qui renvoietrueconstitue un défaut, pas un choix de configuration.
Performances
Section intitulée « Performances »Une vérification de politique est un appel de prédicat : O(1), sans coût proportionnel à l’entrée. La politique est consultée par balise, attribut, propriété CSS et URL pendant l’analyse. Un document pathologique multiplie le nombre d’appels. Chaque appel reste à temps constant. Le performance_budget de 1500 ms de temps réel et 64 Mo en pic mémoire est dominé par l’analyse et le rendu, pas par l’évaluation de la politique. Les plafonds de taille d’entrée et de profondeur d’imbrication existent pour borner le coût propre de l’analyseur. Une politique stricte améliore les performances dans le pire cas en rejetant un document surdimensionné ou trop profondément imbriqué avant la mise en page.
Notes de sécurité
Section intitulée « Notes de sécurité »Ces contrats forment le périmètre défensif du moteur ; le modèle de menace est donc explicite. La rétrogradation d’algorithme est atténuée par CryptoPolicyInterface, qui bloque les hachages faibles et les clés courtes avant toute opération. Le cross-site scripting dirigé vers PDF et l’injection de contenu sont atténués par HtmlSecurityPolicyInterface, qui supprime les balises, attributs et CSS non autorisés au niveau de l’analyse, avant l’exécution du moteur de rendu. La falsification de requête côté serveur, les bombes de décompression et les bombes de taille cumulée sont atténuées par ExternalResourcePolicyInterface, qui adopte deny-all par défaut et borne chaque récupération par schéma, taille, profondeur et domaine. L’épuisement des ressources est atténué par les plafonds de taille d’entrée, de profondeur d’imbrication, de glyphes de police et de profondeur d’import. Parce que chaque politique est un contrat, un déploiement peut durcir le périmètre sans forker le moteur, et le nom de la politique est exposé pour la journalisation d’audit. Traite tout le HTML, toutes les URL et tous les octets de polices et d’images comme hostiles. Cette page est marquée export_control_class: legal-review-required parce que les contrats régissent la politique cryptographique ; la prose paraphrase toutes les sources normatives et n’en cite aucune.
Conformité
Section intitulée « Conformité »| Affirmation | Norme | Clause | Preuve |
|---|---|---|---|
| Une gestion d’URL non contrainte permet de contourner le contrôle d’accès en modifiant l’URL, ce que la politique des ressources externes atténue par ses valeurs par défaut deny-all et par une liste blanche de domaines à correspondance exacte. | OWASP Top 10 2025 | A01 | |
| Les composants externes doivent être obtenus uniquement depuis des sources officielles, via des liens sécurisés, ce que la politique impose à l’aide de listes blanches de schémas. | OWASP Top 10 2025 | Chaîne d’approvisionnement logicielle |
Les deux points sont paraphrasés à partir des recommandations OWASP. Le contenu OWASP est référencé par clause ; le moteur n’en reproduit pas le texte.
Contexte commercial
Section intitulée « Contexte commercial »Le cœur définit et fige les trois contrats de politique. Il fournit des valeurs par défaut permissives pour le développement, ainsi que des valeurs par défaut strictes pour la politique de ressources deny-all. L’édition Enterprise fournit un profil FIPS 140-3 au travers de CryptoPolicyInterface : un déploiement soumis à une réglementation gagne ainsi une posture algorithmique validée sans modifier le code de signature ni de chiffrement. La surface contractuelle est identique d’une édition à l’autre. La différence tient à l’implémentation de politique qu’un déploiement injecte.
Voir aussi
Section intitulée « Voir aussi »- Contracts : 41 interfaces publiques (SPI) — la vue d’ensemble du SPI et les niveaux de stabilité.
- Contracts / Signing —
CryptoPolicyInterfaceappliqué à la signature. - Contracts / Document — les points d’entrée
writeHtml()etimage()contrôlés par ces politiques. - Security — la surface de chiffrement que la politique cryptographique restreint.
- HTML — le pipeline d’analyse que les politiques HTML et de ressources protègent.
- Audit — la journalisation d’audit du nom de politique.