Enterprise édition
Content Disarm and Reconstruction — Référence approfondie
Cette page est la référence approfondie du module NextPDF\Enterprise\Security\Cdr. Le module désarme un PDF non fiable et reconstruit un fichier propre à partir de ses objets sûrs. Le pipeline est le suivant : analyse, contrôle d’admission, détection des menaces, filtrage, nettoyage des références, reconstruction. La sortie est une projection de sécurité de l’entrée, jamais une copie probante. Pour des conseils sur le flux de travail, lis d’abord la page de capacité CDR.
Disponibilité et licence
Section intitulée « Disponibilité et licence »Cette capacité est livrée dans NextPDF Enterprise (nextpdf/enterprise) et s’active avec une enveloppe de licence de niveau Enterprise. Un déploiement dépourvu de cette autorisation ne charge pas les classes de la capacité. Compare les éditions et obtiens une licence.
Surface de l’API publique
Section intitulée « Surface de l’API publique »| Symbole | Paramètres | Comportement par défaut | Retourne | Lève ou échoue avec | Notes |
|---|---|---|---|---|---|
CdrEngine::__construct | aucun | Construit le détecteur et le reconstructeur internes | CdrEngine | Rien de déclaré | Aucun collaborateur injectable |
CdrEngine::sanitize | string $pdfData, ?CdrPolicy $policy = null | Exécute le pipeline complet sous CdrPolicy::standard() | CdrResult | Ne lève pas d’exception sur une entrée hostile ; les échecs d’analyse et d’admission retournent un résultat rejeté | Le résultat signale le rejet distinctement de l’assainissement |
CdrPolicy::__construct | sept paramètres nommés optionnels, voir l’encart | Jeu de suppression vide ; allowUriActions false ; flattenIncrementalUpdates true ; limites de 100000 objets, 256 MiB décodés, 10000 pages, inflation 1000.0 | CdrPolicy | Rien de déclaré | final readonly ; une liste removeThreatTypes vide ne détecte rien |
CdrPolicy::standard | aucun | Jeu de menaces historique ; actions URI supprimées ; limites par défaut | self | Rien de déclaré | Exclut les sept cas Strip* à perte |
CdrPolicy::paranoid | aucun | Jeu de menaces historique avec des limites plus strictes : 50000 objets, 128 MiB, 5000 pages, inflation 100.0 | self | Rien de déclaré | Exclut les sept cas Strip* à perte |
CdrPolicy::permissive | aucun | Supprime uniquement JavaScript, LaunchAction, NamedJavaScript, SubmitForm, ImportData ; préserve les actions URI | self | Rien de déclaré | Destiné aux sources fiables |
CdrPolicy::allThreatTypes | aucun | Retourne tous les cas ThreatType, y compris les cas Strip* à perte | list<ThreatType> | Rien de déclaré | L’activation explicite du décapage maximal |
CdrPolicy::legacyThreatTypes | aucun | Retourne tous les cas sauf les sept cas Strip* | list<ThreatType> | Rien de déclaré | Jeu de suppression par défaut pour standard() et paranoid() |
CdrPolicy::shouldRemove | ThreatType $type | Test d’appartenance à removeThreatTypes | bool | Rien de déclaré | Retourne false pour UriAction quand allowUriActions vaut true |
ThreatDetector::detect | PdfReader $reader, CdrPolicy $policy | Analyse chaque objet et le catalogue du trailer à la recherche des types de menaces de la politique | list<DetectedThreat> | Ne lève pas d’exception ; un objet non analysable devient une menace UnparseableObject | L’analyse du catalogue couvre l’arbre /Names/JavaScript |
CdrRebuilder::rebuild | PdfReader $reader, list<int> $safeObjNums, list<int> $removedObjNums, CdrPolicy $policy | Sérialise les objets sûrs dans un fichier %PDF-2.0 à révision unique | string | Rien de déclaré ; les objets qui échouent à la relecture ou à la validation /Length sont ignorés | $policy est réservé pour de futurs ajustements de sérialisation |
DetectedThreat::__construct | ThreatType $type, int $objectNumber, string $description, string $location = '' | Objet-valeur de constat immuable | DetectedThreat | Rien de déclaré | Les quatre propriétés sont public readonly |
ThreatType | énumération adossée à des chaînes | Vingt cas : treize historiques plus sept cas Strip* optionnels | n/a | n/a | Voir l’inventaire des cas ci-dessous |
Signatures des points d’entrée
Section intitulée « Signatures des points d’entrée »final class CdrEngine{ public function __construct()
public function sanitize(string $pdfData, ?CdrPolicy $policy = null): CdrResult}final readonly class CdrPolicy{ public function __construct( public array $removeThreatTypes = [], public bool $allowUriActions = false, public bool $flattenIncrementalUpdates = true, public int $maxObjects = 100_000, public int $maxDecodedStreamBytes = 268_435_456, public int $maxPageCount = 10_000, public float $maxInflationRatio = 1000.0, )
public static function standard(): self
public static function paranoid(): self
public static function permissive(): self
public static function allThreatTypes(): array
public static function legacyThreatTypes(): array
public function shouldRemove(ThreatType $type): bool}final class ThreatDetector{ public function detect(PdfReader $reader, CdrPolicy $policy): array}final class CdrRebuilder{ public function rebuild(PdfReader $reader, array $safeObjNums, array $removedObjNums, CdrPolicy $policy): string}final readonly class DetectedThreat{ public function __construct( public ThreatType $type, public int $objectNumber, public string $description, public string $location = '', )}enum ThreatType: stringInventaire des cas ThreatType
Section intitulée « Inventaire des cas ThreatType »Treize cas historiques forment le jeu de suppression par défaut. Les cas Strip* sont à perte par conception et n’entrent jamais dans une politique par défaut.
| Cas | Valeur d’adossement | Surface de détection |
|---|---|---|
ThreatType::JavaScript | javascript | Clé /JS sur n’importe quel objet, ou une action /S /JavaScript |
ThreatType::AdditionalActions | additional-actions | Dictionnaire /AA sur n’importe quel objet |
ThreatType::OpenAction | open-action | Clé /OpenAction sur n’importe quel objet |
ThreatType::LaunchAction | launch-action | Action /S /Launch |
ThreatType::RemoteGoTo | remote-goto | Action /S /GoToR ou /S /GoToE |
ThreatType::SubmitForm | submit-form | Action /S /SubmitForm |
ThreatType::ImportData | import-data | Action /S /ImportData |
ThreatType::EmbeddedFiles | embedded-files | Arbre de noms /EmbeddedFiles ou dictionnaire /EF |
ThreatType::RichMedia | rich-media | /Subtype /RichMedia |
ThreatType::NamedJavaScript | named-javascript | Arbre de noms /Names/JavaScript du catalogue |
ThreatType::UriAction | uri-action | Action /S /URI ; supprimée quand allowUriActions vaut true |
ThreatType::Xfa | xfa | Clé /XFA |
ThreatType::UnparseableObject | unparseable-object | Tout objet ou catalogue qui échoue à l’analyse |
ThreatType::StripJavaScript | strip-javascript | Sur-ensemble optionnel : clé /JS, /S /JavaScript, ou /Subtype /JavaScript |
ThreatType::StripEmbeddedFiles | strip-embedded-files | Optionnel : /Type /EmbeddedFile, /Type /Filespec, /EmbeddedFiles, ou /EF |
ThreatType::StripFormFields | strip-form-fields | Optionnel : /Subtype /Widget, clé /FT, ou clé /AcroForm |
ThreatType::StripAnnotationsRich | strip-annotations-rich | Sous-types optionnels : Movie, Sound, FileAttachment, 3D, RichMedia, Screen |
ThreatType::StripOcgNonDefault | strip-ocg-non-default | Optionnel : /Type /OCG avec une clé /Usage ou /Visibility |
ThreatType::StripDigitalSignaturesAtRebuild | strip-digital-signatures-at-rebuild | Optionnel : /Type /Sig, /FT /Sig, /DSS, /VRI, ou /ByteRange |
ThreatType::Strip3dAndRichMedia | strip-3d-and-rich-media | Sous-types optionnels : 3D, U3D, PRC, RMF, RichMedia, Sound, Movie |
Contrat de comportement
Section intitulée « Contrat de comportement »CdrEngine::sanitize exécute six phases ordonnées et ne lève jamais d’exception pour une entrée hostile.
- Analyse. Un échec d’analyse retourne un résultat avec
admittedà false et un motif de rejet d’erreur d’analyse. La sortie assainie est vide dans ce cas. - Contrôle d’admission. Le nombre d’objets, le total des octets de flux décodés, le ratio d’inflation par flux et le nombre de pages sont vérifiés par rapport aux limites de la politique. Un document hors limites est rejeté, pas assaini. Le rejet et l’assainissement sont signalés distinctement.
- Détection.
ThreatDetector::detectanalyse chaque objet et le catalogue du trailer à la recherche des types de menaces de la politique. Les objets non analysables sont enregistrés comme des constatsThreatType::UnparseableObjectplutôt qu’ignorés. - Filtrage. Les objets porteurs de constats sont mis en file d’attente pour suppression. Le catalogue du document n’est jamais supprimé en tant qu’objet entier. Les constats au niveau du catalogue (
OpenAction,AdditionalActions,NamedJavaScript) sont remédiés par décapage de clés à la place. - Nettoyage des références. Chaque référence indirecte vers un objet supprimé est remplacée par
nullpendant la sérialisation. - Reconstruction.
CdrRebuilder::rebuildémet un fichier%PDF-2.0à révision unique avec des objets renumérotés, une table de références croisées classique et un trailer neuf. Les octets de flux sûrs sont copiés à l’identique octet pour octet. Le catalogue reconstruit abandonne/OpenAction,/AAet/Names;/AAest abandonné de chaque objet.
Le CdrResult retourné expose les octets reconstruits, la liste des menaces supprimées, les deux tailles en octets, l’indicateur d’admission et le motif de rejet. Si la source avait un /Root résoluble et que la sortie reconstruite l’a perdu, le moteur rejette la sortie au lieu de retourner un fichier structurellement cassé. C’est une garantie fail-closed : admitted à true implique que la sortie porte encore une référence au catalogue du document.
Les mises à jour incrémentales ne survivent jamais : la reconstruction sérialise exactement une révision sous chaque politique, si bien que les révisions tardives de type shadow sont aplaties par construction. Les signatures numériques d’origine ne peuvent pas rester valides après une reconstruction, car les plages d’octets ne correspondent plus à la sortie.
Ligne rouge d’architecture. Le CDR est une couche de projection de sécurité, pas une couche de préservation. La sortie ne doit pas être utilisée pour la préservation de preuves légales, la comparaison de hachage avec l’original, ou les copies d’archivage.
Cas limites et modes de défaillance
Section intitulée « Cas limites et modes de défaillance »- Une politique
nullse résout enCdrPolicy::standard(). Une politique construite avec leremoveThreatTypesvide par défaut ne détecte et ne supprime rien. allowUriActionsàtruesupprime le retrait deUriActionmême quand le cas est présent dansremoveThreatTypes.flattenIncrementalUpdatesest déclaratif dans cette version : la reconstruction émet une seule révision sous chaque politique, y comprispermissive(), qui met l’indicateur àfalse.- Le contrôle du ratio d’inflation traite une longueur de flux brut de zéro comme un, de sorte qu’un flux qui se gonfle à partir de rien reste borné. Quand aucune forme décodée n’est conservée, la longueur du flux brut compte dans le budget agrégé.
- Le contrôle d’admission du nombre de pages est au mieux : un échec de lecture du catalogue ou de l’arbre des pages ne rejette pas le document à lui seul. Les budgets de nombre d’objets et de décompression sont toujours appliqués.
- Un objet dont la longueur de flux brut diffère de son entrée entière
/Lengthest ignoré au moment de la reconstruction (défense polyglotte). Une référence vers un tel objet ignoré conserve son numéro d’objet source et peut ne pas se résoudre dans la sortie.sanitize()refuse les résultats détectablement cassés (un/Rootmanquant), mais un appelant qui pilote directement le bas niveauCdrRebuilder::rebuild()doit revalider lui-même la structure de sortie et l’intégrité des références. - Quand le trailer source porte
/ID, le trailer reconstruit porte un/IDaléatoire fraîchement généré, pas l’original. Les autres entrées du trailer, y compris/Info, ne sont pas reportées ; le trailer reconstruit contient/Size,/Rootquand il est résoluble, et le/IDrégénéré. - Les octets de noms et de clés décodés sont réémis avec des échappements hexadécimaux pour les délimiteurs, les espaces et les octets non imprimables, de sorte que des noms hostiles ne peuvent pas injecter de syntaxe de dictionnaire dans la sortie.
- Les valeurs de chaîne sous des clés de dictionnaire hors de l’ensemble connu de clés à valeur de nom sont émises de manière conservatrice comme des chaînes littérales.
CdrPolicy::legacyThreatTypes()traite tout futur cas d’énumération comme supprimé par défaut sauf s’il est enregistré comme casStrip*, de sorte que de nouveaux cas à perte ne peuvent pas entrer silencieusement dans les politiques par défaut.- Le CDR n’est pas un module cryptographique. Son seul usage d’aléa est le
/IDrégénéré du trailer. La validation de signature est hors du périmètre ici ; voir la référence approfondie sur les signatures.
Conformité
Section intitulée « Conformité »| Affirmation | Standard | Clause |
|---|---|---|
| L’invocation d’une action ECMAScript fait exécuter le script intégré par un processeur PDF. | ISO 32000-2 | §12.6.4.17 |
Les scripts au niveau du document dans l’arbre de noms JavaScript s’exécutent tous à l’ouverture du document. | ISO 32000-2 | §12.6.4.17 |
Le dictionnaire de noms du catalogue peut contenir un arbre de noms JavaScript d’actions de script au niveau du document. | ISO 32000-2 | §7.7.4 (Table 32) |
| Une action de lancement lance une application, ou ouvre ou imprime un document. | ISO 32000-2 | §12.6.4.6 |
Les dictionnaires d’actions additionnelles /AA étendent les événements déclencheurs sur les annotations, les pages, les champs et le catalogue. | ISO 32000-2 | §12.6.3 |
| L’ingestion de fichiers non fiables doit borner la présence, le volume et le contenu des fichiers entrants. | OWASP ASVS 5.0 | §5.2 |
| Les systèmes devraient empêcher l’exécution inappropriée des fichiers téléversés et détecter les contenus dangereux. | OWASP ASVS 5.0 | §5.3 |
Toutes les clauses sont paraphrasées ; NextPDF ne reproduit pas de texte normatif. NextPDF ne formule aucune revendication de certification. Le CDR retire les surfaces de contenu actif énumérées par ThreatType selon la politique configurée ; c’est une capacité, pas un assainisseur certifié. Le CDR n’est pas un antivirus et ne détecte pas de signatures de logiciels malveillants ; il complète, et ne satisfait pas, des contrôles tels que l’analyse antivirus OWASP ASVS 5.4.3. Savoir si un fichier désarmé est acceptable pour un pipeline d’ingestion donné reste la décision de risque de l’opérateur.
Notes de développement
Section intitulée « Notes de développement »- La source du module porte
@since 1.9.0; cette référence documente la surface telle que livrée dansnextpdf/enterprise3.1.0. - Tout s’exécute dans le processus sur ton hôte. Aucun accès réseau n’a lieu pendant l’assainissement.
CdrPolicyetDetectedThreatsontfinal readonly; construis une nouvelle instance de politique pour changer les limites.CdrEngineconstruit son détecteur et son reconstructeur en interne.ThreatDetectoretCdrRebuilderrestent directement utilisables pour des pipelines par étapes qui fournissent leur proprePdfReader.- Le paramètre
$policydeCdrRebuilder::rebuildest actuellement réservé ; la source le documente comme conservé pour la compatibilité des sites d’appel et de futurs ajustements de sérialisation par politique. - La sortie est reproductible structurellement, pas au bit près : le
/IDrégénéré diffère à chaque exécution quand la source en portait un. - Le type de résultat
CdrResult(valeur de retour desanitize()) est couvert comportementalement ci-dessus ; ses champs sontpublic readonly, avechadThreats()etthreatCount()comme commodités.
Voir aussi
Section intitulée « Voir aussi »- Content Disarm and Reconstruction (CDR) — la page de capacité avec le flux de travail et les conseils de politique.
- Sécurité — Référence approfondie
- Validation — Référence approfondie
- Analyse forensique — Référence approfondie
Périmètre de publication
Section intitulée « Périmètre de publication »Cette page documente uniquement le comportement observable de l’extérieur et la surface d’API publique prise en charge. Les chemins de namespace internes, les classes utilitaires, les tables de mécanismes, les noms de fichiers de runbook et les préfixes de tickets sont hors du périmètre.