Niet-vertrouwde PDF's saneren: content disarm en reconstructie
Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4
In een oogopslag
Sectie met titel “In een oogopslag”Een PDF die uit de buitenwereld binnenkomt, is net zozeer code als een document. Hij kan JavaScript dragen, een Launch action, een ingebed executable, en een structuur die is gemaakt om een parser te laten struikelen. Content Disarm & Reconstruction (CDR) behandelt dat bestand als niet-vertrouwd, houdt alleen wat veilig is, en herbouwt een schone PDF uit de overlevenden.
Deze pagina legt uit hoe de CdrEngine van NextPDF Enterprise dat doet — en het
ene eerlijke ding dat elke CDR-leverancier hardop zou moeten zeggen: het herbouwde
bestand is een security projection van het origineel, geen getrouwe kopie ervan.
Waarom dit belangrijk is
Sectie met titel “Waarom dit belangrijk is”De gevaarlijke delen van een PDF zijn niet exotisch. Het zijn standaardfuncties. De specificatie definieert een hele catalogus van actions — wat er gebeurt wanneer een document opent, wanneer een pagina wordt getoond, wanneer een veld verandert — en die catalogus omvat JavaScript- en Launch actions (Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4). Een viewer die het formaat respecteert, zal ze gewillig uitvoeren. Dat is het houvast van de aanvaller: een bestand dat tegelijk perfect geldig en perfect kwaadaardig is.
Filteren op bestandsextensie doet hier niets. De dreiging zit binnen in een goedgevormde PDF, dus de enige echte verdediging is hem openen, begrijpen, en de actieve machinerie strippen voordat hij ooit een renderer bereikt. Dit is de input-validatiehouding die OWASP’s file-upload- en input-validatierichtlijn beschrijft: vertrouw de bytes nooit, en geef de voorkeur aan het herbouwen van een bekend-goed artefact boven het scannen van een vijandig bestand op bekend-slechte signatures.
De korte versie
Sectie met titel “De korte versie”- CDR neemt aan dat de invoer vijandig is en produceert een nieuw bestand in plaats van het oude te patchen.
CdrEngine::sanitize()draait zes fasen: parse, admission control, threat detection, filter, reference scrub, rebuild.- Het geeft een
CdrResultterug die je vertelt wat is verwijderd, of het document überhaupt is toegelaten, en — zo niet — waarom het is afgewezen. - De uitvoer is een security projection. Het is expliciet geen bewijswaardige kopie, hash-match of archiefartefact. Dat is een contract, geen kanttekening.
- Dit is alleen Enterprise. NextPDF core voert geen CDR uit.
Hoe NextPDF dit aanpakt
Sectie met titel “Hoe NextPDF dit aanpakt”De eigen documentatie van de engine vermeldt de ontwerp-rode-lijn in drie woorden:
Security Projection Layer. sanitize() is een destructieve, onomkeerbare
transformatie. Het mag bytes weggooien. Wat het niet mag doen, is doen alsof het
resultaat hetzelfde document is.
De pijplijn is bewust geordend. Elke fase versmalt het vertrouwen voordat de volgende fase erop handelt.
- ParsePdfReader builds the object graph from the raw bytes. A parse failure is a rejection, not a best-effort guess.
- Admission controlResource limits are checked first — object count, page count, decoded-stream size, per-stream inflation ratio. Over-budget input is rejected, never sanitised.
- DetectThreatDetector walks the graph and records each dangerous feature as a DetectedThreat with its object number and type.
- FilterObjects are partitioned into safe and removed. Catalog-level keys are stripped in place so the document catalog itself survives.
- Reference scrubPointers to removed objects are cleaned so the rebuilt file has no dangling references.
- RebuildCdrRebuilder serialises only the safe objects into a new PDF. The output is fresh structure, not an edited original.
Toelating vóór ontwapening. Voordat ook maar één dreiging wordt verwijderd,
vraagt de engine of het document überhaupt het verwerken waard is. CdrPolicy
draagt de limieten — maxObjects, maxPageCount, maxDecodedStreamBytes en een
maxInflationRatio die verdedigt tegen decompressiebommen. Een document dat daar
ruim overheen gaat, wordt afgewezen, en de CdrResult zegt dat met
admitted: false en een rejectionReason. Dit onderscheid is dragend: “we hebben
het opgeschoond” en “we hebben het geweigerd” zijn verschillende uitkomsten, en het
resulttype houdt ze uit elkaar zodat jouw foutrapportage dat ook kan.
Dreigingen worden benoemd, niet geraden. ThreatDetector::detect() brengt
elke gevaarlijke constructie in kaart op een ThreatType — JavaScript,
LaunchAction, OpenAction, AdditionalActions, RemoteGoTo, SubmitForm,
ImportData, EmbeddedFiles, RichMedia, NamedJavaScript, en meer — elk
gekoppeld aan een specifieke PDF-functie. Een object dat helemaal niet kan worden
geparsed, wordt zijn eigen threat type, UnparseableObject, omdat een object dat
de sanitizer niet kan lezen, een object is waar het niet voor kan instaan. Elke
bevinding is een DetectedThreat die het overtredende objectnummer draagt, zodat
verwijdering precies is.
Verwijdering beschermt het document, niet alleen de payload. Sommige
gevaarlijke sleutels leven op de document catalog (de Root) — een /OpenAction die
bij het openen afgaat, bijvoorbeeld. Het hele Root-object verwijderen om één sleutel
te doden zou de catalog vernietigen en het bestand stilletjes breken. De engine
behandelt deze in plaats daarvan als in-place key strips op de catalog, en als
fail-closed-bewaking weigert het een herbouwd document uit te sturen dat zijn
/Root helemaal is kwijtgeraakt. Een sanitizer die een structureel kapot bestand
produceert terwijl hij succes rapporteert, is precies de faalwijze die deze
bewaking bestaat om te voorkomen.
Praktisch voorbeeld
Sectie met titel “Praktisch voorbeeld”De vorm hieronder is het echte instappunt. Je geeft de engine ruwe bytes en een
policy; je krijgt een CdrResult terug die eerlijk is over wat er is gebeurd.
<?php
declare(strict_types=1);
use NextPDF\Enterprise\Security\Cdr\CdrEngine;use NextPDF\Enterprise\Security\Cdr\CdrPolicy;
$engine = new CdrEngine();
// Standard policy removes the known active threats — JavaScript, Launch// actions, remote go-to, form submit/import, and the rest — while leaving// the lossy opt-in "Strip*" cases off by default.$result = $engine->sanitize($untrustedPdfBytes, CdrPolicy::standard());
if (!$result->admitted) { // Rejected by admission control (e.g. object/page limit, zip bomb). // This is NOT a sanitised document. Do not serve it; report the reason. throw new \RuntimeException($result->rejectionReason);}
if ($result->hadThreats()) { // The disarmed bytes are safe to render. Each removed threat carries its // type and object number for your audit log — never silently. foreach ($result->removedThreats as $threat) { error_log(\sprintf( 'CDR removed %s in object %d', $threat->type->value, $threat->objectNumber, )); }}
$cleanBytes = $result->sanitizedPdf; // The security projection. Not the original.Er is geen pad waar deze code stilletjes een nog-gevaarlijk bestand teruggeeft.
Ofwel het document is toegelaten en ontwapend, ofwel het is afgewezen met een
vermelde reden. De removedThreats-lijst betekent dat de ontwapening auditeerbaar
is, niet magisch.
Veelvoorkomend misverstand
Sectie met titel “Veelvoorkomend misverstand”“CDR is gewoon redactie met extra stappen.”
Dat is het niet, en de twee samensmelten is gevaarlijk. Redactie verwijdert informatie — namen, rekeningnummers, de inhoud die een mens niet mag zien. CDR verwijdert capaciteit — de JavaScript, de Launch action, de ingebedde payload die een machine niet mag uitvoeren. Ze hebben tegengestelde succescriteria. Een redactie is correct wanneer gevoelige inhoud weg is en de rest woordelijk behouden blijft. Een ontwapening is correct wanneer de dreiging weg is, en het is volkomen bereid om goedaardige structuur te wijzigen om daar te komen. Gebruik de tool die bij je bedoeling past; grijp er geen in de verwachting van de garanties van de ander.
Een tweede misverstand is dat een schone herbouw bewijst dat het origineel schoon was. Het bewijst niets over het origineel. Het bewijst alleen dat de uitvoer geen gedetecteerde dreiging bevat. De invoer kan een wapen zijn geweest; CDR’s taak is ervoor te zorgen dat wat je verderop in de keten doorstuurt dat niet is.
Grenzen en beperkingen
Sectie met titel “Grenzen en beperkingen”Dit is het deel dat de brochures overslaan, dus we zeggen het ronduit.
- De uitvoer is een security projection, geen bewijswaardige kopie. De bron van
de
CdrEnginedraagt dit als een architecturale rode lijn. De gesaneerde PDF mag niet worden gebruikt voor juridische bewijsbewaring, voor hashvergelijking tegen het origineel, of als archiefkopie. De transformatie is destructief en bij ontwerp onomkeerbaar. - Detectie heeft een reikwijdte. CDR verwijdert de dreigingen die het kan benoemen. Het is een sterke, auditeerbare laag in een defense-in-depth-stack — geen garantie dat een bestand vrij is van elke mogelijke toekomstige techniek. Houd het achter dezelfde upload-validatie, content-type-controles en least-privilege-afhandeling die OWASP’s file-upload-richtlijn beschrijft.
- Sommige policies zijn opzettelijk lossy. De opt-in
Strip*-gevallen verwijderen ingebedde bestanden, handtekeningen, formuliervelden, lagen en 3D-media. Die zijn krachtig en zullen legitieme inhoud verwijderen — een ZUGFeRD/Factur-X-factuur-payload, bijvoorbeeld. Ze staan om precies die reden standaard uit. Zet ze bewust aan. - Handtekeningen overleven een herbouw niet. Het bestand reconstrueren verandert zijn bytes, dus elke oorspronkelijke digitale handtekening komt niet langer overeen met zijn bytebereik. Een ontwapend document is niet-ondertekend ten opzichte van de bron. Als je een ondertekend artefact nodig hebt, onderteken dan de schone uitvoer als een nieuwe handeling.
| Edition | Availability |
|---|---|
| Core | Not available. NextPDF core does not perform CDR. It parses, renders, and writes PDFs; it does not threat-detect or rebuild untrusted input. |
| Pro | Not available in the Pro edition. |
| Enterprise | Available via |
Verwante documentatie
Sectie met titel “Verwante documentatie”- Hoe PDF-versleuteling echt werkt — de andere helft van het omgaan met gevoelige PDF’s: inhoud beschermen versus capaciteit verwijderen.
- Fouten als een functie — de
fail-closed-filosofie die CDR’s admission-control-afwijzingen en
/Root-bewaking belichamen. - Een API die weigert te gokken — waarom een resulttype dat opgeschoond van afgewezen onderscheidt een stille best-effort verslaat.
Woordenlijst
Sectie met titel “Woordenlijst”- CDR (Content Disarm & Reconstruction) — een saneringsstrategie die een niet-vertrouwd bestand parsed, actieve of gevaarlijke componenten verwijdert, en een schoon bestand herbouwt uit de veilige rest, in plaats van te scannen op bekend-slechte signatures.
- Security projection — een gesaneerde uitvoer die genoeg van de bron behoudt om nuttig te zijn terwijl het de verwijdering van dreigingen garandeert. Het is bewust niet byte-getrouw en niet geschikt voor bewijs, hashing of archivering.
- Admission control — de pre-saneringspoort die documenten afwijst die resourcelimieten overschrijden (objectaantal, paginaaantal, gedecodeerde-stream-grootte, inflatieratio) voordat enig ontwapeningswerk begint.
- Action — een PDF-constructie die iets laat gebeuren bij een trigger zoals document-open of een veldwijziging; de action-type-catalogus (Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4) omvat JavaScript- en Launch actions, het canonieke CDR-dreigingsoppervlak.
- Bungelende referentie — een verwijzing naar een object dat na het filteren niet meer bestaat. De reference-scrub-fase verwijdert deze zodat het herbouwde bestand structureel consistent blijft.