Aller au contenu

Sécurité et exploitation de compat-legacy

L’adaptateur hérite du modèle de sécurité du moteur NextPDF et ajoute quelques durcissements délibérés par rapport au TCPDF hérité 6.2.13. Cette page précise ce qui est disponible et ce qui ne l’est pas, sans surestimer les capacités. Lis attentivement la section sur la signature — sa portée est volontairement restreinte.

Trois comportements historiques de TCPDF 6.2.13 sont modifiés par sécurité et ne peuvent pas être reconfigurés dans leur forme dangereuse :

Point concernéTCPDF hérité 6.2.13Adaptateur
Gestion des erreursError() appelle die() et met fin au processusError() lève une RuntimeException. L’échec est observable, interceptable, sans arrêt silencieux du processus.
Exécution de HTMLUne porte dérobée pouvait exécuter du PHP depuis le balisageLa constante K_TCPDF_CALLS_IN_HTML est figée à false ; le balisage ne peut pas déclencher l’exécution de PHP.
Sortie directeOutput() écrit dans le tampon de sortie actifLa sortie est acheminée via un pont de destination sûr. Elle ne pollue pas un tampon de sortie contrôlé par l’appelant.

La modification de la gestion des erreurs suit le principe selon lequel un appelant doit pouvoir observer un échec, plutôt que de voir le processus s’interrompre brutalement. OWASP ASVS 5.0 §16.5.3 indique qu’une application doit échouer proprement et en sécurité, et empêcher les conditions de défaillance ouverte. Le passage de « die » à la levée d’exception applique ce principe. Le durcissement du HTML supprime un point d’exécution de code. Considère tout code hérité qui dépendait de l’ancien comportement comme un défaut à corriger lors de /integrations/tcpdf-compat/migration/. Le récapitulatif des clauses épinglées se trouve dans le front-matter citations de la page.

L’adaptateur expose la méthode SetProtection() de TCPDF. Celle-ci délègue au gestionnaire de sécurité standard du moteur NextPDF.

  • Le gestionnaire standard utilise AES-256. Le paramètre hérité $mode est accepté pour conserver la compatibilité de signature et ignoré — il n’existe aucun moyen de sélectionner un chiffrement plus faible via cette méthode. Avec le mode strict activé, un $mode non par défaut lève une exception, ce qui force la migration à le traiter explicitement (vérifié dans tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php).
  • Si aucun mot de passe propriétaire n’est fourni, l’adaptateur génère un mot de passe propriétaire aléatoire et cryptographiquement robuste plutôt que de réutiliser le mot de passe utilisateur. Cela empêche les détenteurs d’un accès de niveau utilisateur d’obtenir un contrôle de niveau propriétaire sur le document.
  • Le chiffrement par certificat (clé publique) ne passe pas par SetProtection() ; son paramètre $pubkeys est ignoré. Utilise le point d’entrée moderne de chiffrement par clé publique exposé par l’adaptateur (setPublicKeyEncryption()), qui délègue au moteur.

Le comportement de chiffrement reflète le gestionnaire de sécurité standard décrit dans ISO 32000-2 §7. Cette clause définit les entrées du dictionnaire de chiffrement et le gestionnaire standard AES-256 qu’utilise le moteur. Cette documentation ne prétend pas que la sortie est « sécurisée par défaut » ou « inviolable ». Elle indique le chiffrement utilisé et le comportement du mot de passe propriétaire, conformément au comportement réel du code. Le récapitulatif des clauses épinglées se trouve dans le front-matter citations de la page.

examples/security-encryption.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Encrypted document');
// User password set; owner password auto-generated (strong, random).
$pdf->SetProtection([], 'user-secret');
$pdf->Output(__DIR__ . '/encrypted.pdf', 'F');

Lis cette section au pied de la lettre. Elle est volontairement prudente.

  • Les méthodes héritées de TCPDF setSignature() et addEmptySignatureAppearance() sont non implémentées dans l’adaptateur sur le moteur principal. Elles ne font rien en mode par défaut et lèvent TcpdfNotImplementedException en mode strict.
  • La signature numérique n’est pas une capacité de la distribution principale via cet adaptateur. La prise en charge de la signature de base est réservée à une édition commerciale de NextPDF.
  • Lorsqu’une édition commerciale est présente, l’adaptateur expose un point d’entrée de signature moderne (setSignatureV2()) qui délègue au moteur. Son profil par défaut est le profil de base (B-B).
  • Cette documentation n’affirme en aucun cas qu’une édition produise des profils de signature horodatés, à validation à long terme ou destinés à l’archivage via cet adaptateur. Plus précisément, elle n’affirme aucun comportement B-T, B-LT ou B-LTA. La spécification de base PAdES §6.1 définit quatre niveaux de base distincts — B-B, B-T, B-LT et B-LTA — chacun avec ses propres exigences. B-B est le niveau de base, et les niveaux supérieurs (horodatage, long terme, archivage) sont des profils distincts et plus exigeants. Seul le niveau de base B-B relève de la portée de la documentation de cette couche de compatibilité. Les niveaux supérieurs sont explicitement hors de portée et ne sont revendiqués ici pour aucune édition. Le récapitulatif des clauses épinglées se trouve dans le front-matter citations de la page.
  • Aucune affirmation de signature « certifiée », « garantie », « juridiquement valable » ou « qualifiée eIDAS » n’est faite où que ce soit. L’exactitude de la signature, la politique d’ancre de confiance et la validité juridique relèvent de la responsabilité de l’édition de signature et de l’IGC de l’appelant, et non de cette couche de compatibilité.

Si ta migration exige la signature, traite-la comme un chantier distinct : adopte l’API de signature moderne sur une édition commerciale et valide la signature produite avec un vérificateur indépendant. Ne te fie pas à l’appel setSignature() de TCPDF — il est sans effet ici.

La méthode héritée setTimeStamp() est acceptée pour conserver la compatibilité de signature et émet un avis ; elle ne produit pas de signature horodatée via cet adaptateur.

L’indicateur pdfa du constructeur est accepté pour conserver la compatibilité de signature. La conformité d’archivage PDF/A nécessite une édition commerciale de NextPDF. L’adaptateur expose enablePdfA() qui délègue au moteur, et le moteur renvoie une erreur de configuration exploitable lorsque l’édition requise est absente. L’adaptateur ne produit pas silencieusement un fichier non conforme tout en prétendant être conforme PDF/A.

La sortie est toujours en PDF 2.0 (ISO 32000-2). ISO 32000-2 §7.5.2 précise qu’un rédacteur conforme identifie la version du document comme étant la 2.0 et ne la rétrograde pas vers une version antérieure dans l’enregistrement. setPDFVersion() ne peut donc pas cibler une version antérieure (voir /integrations/tcpdf-compat/method-coverage/ §4). Le récapitulatif des clauses épinglées se trouve dans le front-matter citations de la page.

  • Aucun arrêt du processus. Comme Error() lève une exception au lieu de die(), encadre les points d’entrée de rendu dans try/catch et traduis les échecs selon le contrat d’erreur de ton application. Ne pars pas du principe qu’un rendu en échec met fin à la requête.
  • Sûreté du tampon de sortie. Output() avec S renvoie des octets ; avec F, écrit un fichier ; avec E, renvoie un corps MIME en base64 ; avec I/D, il passe par le chemin de sortie du moteur. Privilégie S ou F dans les workers et les gestionnaires HTTP afin de contrôler toi-même la réponse — voir /integrations/tcpdf-compat/production-usage/.
  • Le mode strict n’est pas un réglage de production. Réserve-le à l’intégration continue ou à l’audit. Une exception dans un chemin de rendu de production est pire qu’un paramètre dégradé en silence.
  • Hygiène des constantes. Définis les constantes PDF_* / K_* avant la première instanciation de l’adaptateur. Les deux indicateurs durcis (K_TCPDF_CALLS_IN_HTML, K_TCPDF_THROW_EXCEPTION_ERROR) ne peuvent pas être assouplis ; n’essaie pas de le faire.
  • Mots de passe propriétaire aléatoires. Si tu comptes sur un mot de passe propriétaire déterministe, définis-le explicitement. Sinon, un mot de passe aléatoire robuste est généré par document et n’est pas récupérable.
  • Pour les méthodes image, un chemin de wrapper de flux est refusé avant toute lecture du système de fichiers. La détection du type d’image (TcpdfImages::getImageFileType) traite tout chemin scheme://phar://, php:// et les autres wrappers de flux PHP — comme un wrapper et évite la sonde file_get_contents / getimagesize, en se rabattant sur une inférence fondée uniquement sur l’extension. Cela ferme un vecteur de désérialisation de métadonnées phar sur la cible de rétroportage PHP 7.4 ; l’intégration du chemin de wrapper elle-même est rejetée par le moteur.
  • L’adaptateur ne valide ni n’assainit par ailleurs les chemins de fichiers transmis aux méthodes d’image ou de sortie au-delà de ce que fait le moteur. Considère les chemins et les URL fournis par l’appelant comme non fiables à la frontière de ton application.
  • Le HTML transmis aux méthodes HTML est rendu par le moteur, et non par un analyseur HTML de TCPDF. Le point d’exécution PHP hérité est fermé, mais le HTML fourni par l’appelant doit néanmoins être traité comme une entrée non fiable.
  • Le chiffrement protège la confidentialité du document au repos selon le gestionnaire standard. Il ne remplace ni la sécurité du transport ni le contrôle d’accès dans ton application.
  • /integrations/tcpdf-compat/method-coverage/ — comportement exact de SetProtection(), setSignature()
  • /integrations/tcpdf-compat/configuration/ — les deux indicateurs durcis et non configurables
  • /integrations/tcpdf-compat/production-usage/ — workers, tampons, gestion des échecs
  • docs/TCPDF_COVERAGE.md — matrice de couverture faisant autorité
  • Fichier NOTICE du paquet — déclaration d’implémentation indépendante