Når bedriftssystemet ditt aksepterer PDF-er fra upålitelige eksterne kilder, er det å behandle hver innkommende fil identisk en oppskrift på ødelagte arbeidsflyter, sikkerhetshendelser og dårlig samsvar med tilgjengelighet. Dokumenter kan inneholde ondsinnede skript, mangle innebygde skrifttyper som kreves for utskrift, eller bestå utelukkende av skannede bilder som forhindrer tekstekstrahering
For å trygt innta dokumenter, trenger du en automatisert inntaksrevisjon og preflight-fase. I denne artikkelen ser vi på hvordan du bygger en robust revisjonsrørledning ved hjelp av Delphi og PDFium-motoren for å klassifisere, validere og rute innkommende PDF-er
Funnposten og kontrakten for avslutningskoder
En inntaksrevisjon skiller seg fra gjengivelse. Det er en rask, hodeløs prosess som skanner dokumentets interne metadata, ordbøker og sidestrukturer for å generere en risikoprofil. Basert på denne profilen utleder systemet en "anbefalt handling" for filen
En robust revisjonsrørledning bør se etter:
- Manglende skrifttypeinnbygging: Dokumenter som mangler innebygde skrifttyper, kan gjengis perfekt på oppretterens maskin, men ødelegges under utskrift på serversiden
- Skannede versus tekstsider: Hvis sidene bare inneholder store bilder og ingen tekstobjekter, må de rutes til en OCR-kø (Optical Character Recognition)
- Samsvar med tilgjengelighet: Mangler skjemafelt verktøytips? Mangler dokumentet et logisk strukturtre (Tagged PDF)? Disse krever utbedring før publisering på nettet
- Aktivt innhold: Eksterne URI-handlinger, innebygd JavaScript eller funksjoner som ikke støttes utgjør sikkerhetsrisikoer og bør utløse en karanteneprotokoll
Interaktive elementer: skript, startmål og eksterne lenker
Et vanlig anti-mønster i revisjonsverktøy er ganske enkelt å dumpe en massiv JSON-fil med tekniske brudd (for eksempel "Warning: XRef stream malformed", "Info: Has JavaScript"). Mens det er nyttig for feilsøking, er dette forferdelig for automatisert batch-prosessering
I stedet bør revisjonen utlede en anbefalt handling basert på et prioritert hierarki. For eksempel:
- Hvis dokumentet kaster et unntak ved innlasting eller har funksjoner som ikke støttes, er handlingen
quarantine - Hvis dokumentet krever et passord for å åpne, er handlingen
request-password - Hvis dokumentet er en ren skanning, er handlingen
run-ocr - Hvis dokumentet mangler tilgjengelighetstagger, er handlingen
remediate-tags - Hvis det ikke finnes noen store brudd, er handlingen
pass-through
Ved å håndheve dette konservative hierarkiet, kan back-end-tjenestene dine ganske enkelt bytte på strengen for anbefalt handling for å bestemme hvilken mikrotjeneste som håndterer filen neste gang
Ressursmålinger: effektiv bilde-DPI
Fordi inntaksrørledningen må behandle tusenvis av dokumenter, må revisjonslogikken være strengt hodeløs. Den bør ikke instansiere noen UI-komponenter, visningstilstander eller kreve en aktiv skjermkontekst
For hvert bilde bør revisjonen beregne effektiv DPI fra pikselmålene og bildets størrelse på siden. Det fanger opp skannede bilder som ser skarpe ut i en visning, men blir uegnede for utskrift
Sikkerhetstilstand: kryptering og tillatelsesbiter
Les krypteringsordboken og tillatelsesbitene som en egen kontroll. Et passord som kan åpne filen sier ikke at utskrift, kopiering eller endring er tillatt for arbeidsflyten som skal bruke den
Standardmarkører: lese et PDF/A-krav
En PDF/A-markør i metadata er et krav som må kontrolleres, ikke et bevis på samsvar. Registrer påstanden separat slik at den kan sammenholdes med en faktisk validator senere
En kjøring mot en problemfil
En testfil bør gi flere funn samtidig, slik at rapporten viser at kontrollene kan kombineres og at avslutningskoden beholder samme betydning gjennom hele batchen
Hva denne revisjonen ikke kan fortelle deg
En PDFium-revisjon kan lese struktur, metadata og risikosignaler, men beviser ikke visuell kvalitet, full PDF/A-samsvar eller at et eksternt mål er trygt. Slike påstander krever egne validerings- og policytrinn
Til slutt, sørg for at utdataformatet ditt er konsistent. Enten du genererer en enkeltfil JSON-rapport eller en batch-aggregert CSV, må utdataskjemaet speile den interne revisjonsposten perfekt. Dette sikrer at automatiseringsskript nedstrøms aldri støter på semantisk glidning
Merk: Omfattende inntaksrevisjon og tilgjengelighetssjekker er innebygde funksjoner i PDFium Component
\nFlere kodeeksempler
uses
System.SysUtils, pdfium_lib;
procedure AuditPdfSecurity(const FileName: string);
var
Doc: FPDF_DOCUMENT;
PageCount, i, j: Integer;
Page: FPDF_PAGE;
AnnotCount: Integer;
Annot: FPDF_ANNOTATION;
AnnotSubType: FPDF_ANNOTATION_SUBTYPE;
Action: FPDF_ACTION;
ActionType: ULONG;
begin
FPDF_InitLibrary();
try
// Load the document without a password
Doc := FPDF_LoadDocument(PAnsiChar(AnsiString(FileName)), nil);
if Doc = nil then
raise Exception.Create('Failed to load document or password required.');
try
PageCount := FPDF_GetPageCount(Doc);
Writeln(Format('Auditing %d pages...', [PageCount]));
for i := 0 to PageCount - 1 do
begin
Page := FPDF_LoadPage(Doc, i);
if Page <> nil then
begin
AnnotCount := FPDFPage_GetAnnotCount(Page);
for j := 0 to AnnotCount - 1 do
begin
Annot := FPDFPage_GetAnnot(Page, j);
if Annot <> nil then
begin
AnnotSubType := FPDFAnnot_GetSubtype(Annot);
// Check for Link Annotations that might have malicious actions
if AnnotSubType = FPDF_ANNOT_LINK then
begin
Action := FPDFAnnot_GetLinkAction(Annot);
if Action <> nil then
begin
ActionType := FPDFAction_GetType(Action);
// 2 represents PDFACTION_URI, 3 represents PDFACTION_SOUND, 4 represents PDFACTION_MOVIE
// We specifically look out for PDFACTION_LAUNCH or PDFACTION_JAVA_SCRIPT
if (ActionType = PDFACTION_JAVA_SCRIPT) or (ActionType = PDFACTION_LAUNCH) then
begin
Writeln(Format('WARNING: Malicious action detected on page %d', [i + 1]));
end;
end;
end;
FPDFPage_CloseAnnot(Annot);
end;
end;
FPDF_ClosePage(Page);
end;
end;
finally
FPDF_CloseDocument(Doc);
end;
finally
FPDF_DestroyLibrary();
end;
end;procedure AuditPageImages(Page: FPDF_PAGE);
var
ObjCount, i: Integer;
PageObj: FPDF_PAGEOBJECT;
ImgWidth, ImgHeight: Integer;
begin
ObjCount := FPDFPage_CountObjects(Page);
for i := 0 to ObjCount - 1 do
begin
PageObj := FPDFPage_GetObject(Page, i);
if FPDFPageObj_GetType(PageObj) = FPDF_PAGEOBJ_IMAGE then
begin
FPDFImageObj_GetBitmap(PageObj); // Returns an FPDF_BITMAP you can inspect
// Retrieve metadata using FPDFImageObj_GetImageMetadata
// Calculate effective DPI based on quad coordinates
end;
end;
end;