Zastavica dovoljenja PDF ni ključavnica. Gre za zahtevo, ki jo datoteka postavi vsakemu programu, ki jo odpre, pregledovalnik pa jo lahko prezre. To dejstvo določa, kako bi morali razmišljati o vseh drugih možnostih na tej strani. Resnična zaupnost izhaja le iz enega mesta: šifriranja AES-256, ki temelji na geslu, ki ga bralec nima. Vse ostalo, kot sta potrditveni polji »brez tiskanja« in »brez kopiranja«, so le pravila, ki jih skladna programska oprema upošteva, zlonamerna pa ne. Če ta dva nivoja pomešate, boste ustvarili nekaj, kar je na predstavitvi videti varno, v praksi pa pušča podatke.
HotPDF je izvorna komponenta VCL PDF za Delphi in C++Builder, ki prek majhnega nabora lastnosti izpostavlja varnostni model ISO 32000. Lastnosti je enostavno nastaviti. Težji del je vedeti, katera lastnost vam prinaša kriptografsko zaščito in katera le vljudno priporočilo, ter pravilno določiti vrstni red dodeljevanja vrednosti, da bo zahtevano šifriranje dejansko uporabljeno.
Kaj dejansko zagotavljata dve gesli
Šifriranje PDF določa dve vrsti poverilnic z različnima nalogama in njuno mešanje je najpogostejša napaka pri načrtovanju kode za zaščiten izhod. Uporabniško geslo (user password) omejuje dešifriranje. Brez njega (ali brez lastniškega gesla) skladen bralnik ne more rekonstruirati ključa datoteke, vsebina pa ostane kriptografsko nečitljiva. Lastniško geslo (owner password) pa nadzoruje nastavitve dovoljenj: bralnik, ki prejme lastniško geslo, dobi poln dostop, ne glede na to, kaj pravijo zastavice omejitev.
Biti dovoljenj so na precej šibkejših tleh. Tiskanje, pridobivanje vsebine, izpolnjevanje obrazcev: vsak od teh elementov je le zastavica, ki jo pregledovalnik prebere in se odloči, ali jo bo spoštoval (ISO 32000-2 §7.6.4). Šifriranje ščiti bajte. Zastavice dovoljenj le dajejo navodila skladni programski opremi, in to šele po dešifriranju. Vsakdo, ki dokument odpre z uporabniškim geslom, že ima dešifrirano vsebino v pomnilniku, zato varnostni omejitvi »prepoved kopiranja« in »prepoved tiskanja« pomenita nekaj le za lepo vzgojen pregledovalnik, za odločnega napadalca pa nič. Na tej podlagi zgradite svoj model groženj. Zaupnost živi v uporabniškem geslu. Dovoljenja le oblikujejo tisto, kar ponujajo običajni pregledovalniki, in to je vse, kar počnejo.
Vrstni red konfiguracije: vse pred klicem BeginDoc
HotPDF zgradi slovar šifriranja in izpelje ključ datoteke v trenutku, ko se zažene BeginDoc. Kakršnekoli so varnostne lastnosti v tistem trenutku, takšne bo dokument prevzel, kasnejše spreminjanje pa ne vpliva na nič. Najpomembnejša lastnost je CryptKeyLength, ki izbere shemo iz vrednosti THPDFKeyType: k40, k128, aes128 in aes256. Če jo dodelite po klicu BeginDoc, ne boste prejeli izjeme ali opozorila, temveč le datoteko, ki je tiho obdržala prvotno nastavitev. Takšno tiho odstopanje je najslabša možna napaka: uspešno prestane vse lokalne teste, mesece kasneje pa se pojavi kot varnostno neskladje na mizi stranke.
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'statement.pdf';
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256; // must be set before BeginDoc
Pdf.UserPassword := 'open-secret';
Pdf.OwnerPassword := 'admin-secret';
Pdf.UseAES256R6 := False; // R=5: widest viewer support
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 720, 0, 'Account statement, June 2026');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Gesla so v formatu UTF-8 in omejena na 127 bajtov, kajti to je omejitev standarda ISO 32000-2 za sheme AES-256. Če vaša politika gesel zahteva daljše skrivnosti, skrajšanje opravite sami na svoji strani, kjer natančno nadzorujete mesto reza. Če to prepustite naključju, se lahko knjižnica in pregledovalnik v prihodnosti ne strinjata glede mesta skrajšanja, kar ustvari datoteko, ki se pri vas odpre, drugje pa isto geslo zavrne.
Revision 5 ali revision 6: ena logična vrednost, dva ekosistema
Lastnost UseAES256R6 izbira med dvema postopkoma AES-256 in ta odločitev prinaša večje posledice, kot nakazuje njen tip Boolean. Če jo pustite na False, bo HotPDF zapisal revizijo 5 (revision 5) – shemo AES-256, ki je prišla kot razširitev za PDF 1.7 in jo lahko odprejo pregledovalniki iz zadnjih petnajstih let. Če jo nastavite na True, dobite revizijo 6 (revision 6), utrjeno izpeljavo ključa, ki je standardizirana v ISO 32000-2 za PDF 2.0 in odpravlja znano ranljivost pri preverjanju gesla v reviziji 5.
Z vidika kriptografije je torej revizija 6 boljša izbira. Vendar pa lahko povzroči težave z združljivostjo. Datoteka revizije 6 zahteva pregledovalnik, zgrajen za PDF 1.7 Extension Level 3 ali PDF 2.0, čemur pa veliko nameščene programske opreme ne ustreza: sistemi za arhiviranje dokumentov, vgrajeni pregledovalniki v drugih izdelkih ali interna poslovna orodja, ki jih že leta nihče ni posodobil. Ta orodja bodo datoteko popolnoma zavrnila, in to se bo zgodilo na računalniku vaše stranke, nikoli na vašem. Praktična privzeta vrednost je zato revizija 5. Po reviziji 6 posezite le takrat, ko varnostna politika izrecno zahteva standard ISO 32000-2 po revizijah in ko ste dejansko potrdili, da jo vsi prejemniki lahko preberejo. V vsakem primeru zabeležite, katero možnost ste izbrali in zakaj, saj se bo naslednji razvijalec te kode zagotovo spraševal o tem.
Starejše vrste ključev si zaslužijo le kratko omembo, da se jim izognete. THPDFKeyType še vedno navaja k40, k128 in aes128, vendar ti obstajajo le za reprodukcijo zgodovinskih arhivov, ne pa za zaščito novih dokumentov. 40-bitni RC4 je enostavno zlomljiv z običajno strojno opremo, 128-bitne sheme pa so starejše od revizij AES-256, ki jih bo pričakoval vsak sodoben varnostni pregled. Za dokument, ki ga ustvarjate danes, je edino resnično vprašanje izbira med revizijo 5 in revizijo 6. Če se zalotite, da pri novem načrtovanju posegate po zastarelih vrstah, je šlo nekaj narobe že pred tem.
Zastavice dovoljenj brez gesla za odpiranje
Pogosto je zahteva ravno nasprotna od tajnosti. Vsakdo bi moral imeti možnost prebrati dokument, vendar naj bi bila omejena možnost tiskanja ali kopiranja vsebine. To izrazite s praznim uporabniškim geslom in nepraznim lastniškim geslom, kar PDF imenuje način z odprtim geslom (open-password mode), dejavnosti, ki jih želite dovoliti, pa navedete v ProtectOptions.
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.UserPassword := ''; // anyone can open the file
Pdf.OwnerPassword := 'rotate-me-quarterly'; // guards the permission set
Pdf.ProtectOptions := [prPrint, prPrint12bit, prExtractContent];
Pdf.BeginDoc;
// ... page content ...
Pdf.EndDoc;
Nabor THPDFProtectOptions se preslika v bite dovoljenj standarda ISO: prPrint in prPrint12bit za tiskanje visoke ločljivosti, prInformationCopy za splošno kopiranje in pridobivanje vsebine, prExtractContent za pridobivanje vsebine s pomočjo asistenčne tehnologije ter dodatno prModifyStructure, prEditAnnotations, prFillAnnotations in prAssemble. Dva od njih si zaslužita opozorilo. Pustite prExtractContent vklopljen v skoraj vsakem profilu, ki ga ustvarite. To je namreč bit, ki ga bralnik zaslona potrebuje za dostop do besedila, njegov izklop pa tiho spremeni odločitev o pravicah v napako dostopnosti, na katero naletijo osebe z invalidnostjo, vi pa je nikoli ne vidite. Druga past je samo prPrint brez prPrint12bit: več pregledovalnikov se odzove tako, da poslabša kakovost tiskanja, vaši uporabniki pa bodo to prijavili kot napako pri izrisu in ne kot nastavitev dovoljenja, kar v resnici je.
Preverjanje traja pet minut in sodi na vaš kontrolni seznam za izdajo. Odprite vzorec vsakega profila v programu Acrobat, odprite lastnosti dokumenta (Document Properties) in si oglejte zavihek Varnost (Security), ki opisuje algoritem (»AES 256-bit«) in navaja dovoljene operacije. Nato isto datoteko odprite v najstarejšem pregledovalniku, ki ga vaše stranke dejansko uporabljajo, in ne v najnovejšem na vašem računalniku. To drugo odpiranje je poceni zavarovanje pred tem, da bi datoteka revizije 6 uspešno prestala razvoj, nato pa odpovedala pri stranki, ki nikoli ni posodobila svoje programske opreme.
Odstranjevanje zaščite iz obstoječih datotek
Dešifriranje deluje po enakem modelu lastnosti, le v obratni smeri. Naložite dokument z veljavno poverilnico, izklopite zaščito in shranite rezultat brez nje.
var
Pdf: THotPDF;
PageCount: Integer;
begin
Pdf := THotPDF.Create(nil);
try
PageCount := Pdf.LoadFromFile('encrypted.pdf', 'open-secret');
if PageCount > 0 then
begin
Pdf.ActivateProtection := False; // drop encryption on save
Pdf.SaveLoadedDocument('plain.pdf');
end;
finally
Pdf.Free;
end;
end;
Ta pot analizira celoten dokument v pomnilnik, kar je v redu za običajne datoteke, potratno pa za velike. Ko vhod obsega več sto megabajtov, je DecryptFile ugodnejša možnost: dešifrira med kopiranjem na ravni datoteke, pri čericom uporabi neposredno pot prepisovanja AES-256, ki preskoči gradnjo celotnega drevesa objektov, kadar vhod to omogoča. To je del vmesnika Direct File API, ki je opisan v spremljajočem članku o obdelavi velikih PDF-jev iz okolja Delphi.
Omejitve, ki vplivajo na šifriranje
Preden začnete načrtovati šifriranje, je dobro poznati dve omejitvi. Prva je arhivska skladnost. Standard ISO 19005 prepoveduje šifriranje v PDF/A, zato je vsak delovni tok, ki šifrira dokument in hkrati zahteva skladnost PDF/A, že po zasnovi protisloven; HotPDF vam ne bo dovolil obojega v isti datoteki. Ko resnično potrebujete oboje, je rešitev v dveh različicah: šifrirana kopija za distribucijo in ločena nešifrirana kopija za arhiv.
Druga omejitev je še bolj izrazita. Šifriranje PDF nima možnosti obnovitve gesla. Če izgubite uporabniško geslo za datoteko R5 or R6, so vaše možnosti le napad z grobo silo (brute force) ali predaja. Zato z lastniškimi in uporabniškimi gesli ravnajte enako kot z drugimi produkcijskimi poverilnicami. Ustvarite jih, jih shranite v varno shrambo (vault) in jih redno menjajte. Nikoli pa jih ne zapisujte neposredno v kodo kot konstante v enoti, saj bodo tako prešle neposredno v nadzor različic in za vedno ostale v delovni kopiji vsakega razvijalca.
In še zadnja navada, ki jo je dobro usvojiti. Spreminjanje zaščite na datoteki, ki je niste sami ustvarili, uporablja enak mehanizem kot dešifriranje in ni ločena funkcija: naložite jo z njenim geslom prek LoadFromFile, uredite ProtectOptions ali gesla na mestu samem ter jo zapišite nazaj s SaveLoadedDocument. Če lahko datoteko dešifrirate, ji lahko tudi spremenite dovoljenja, koda pa je skoraj identična zgornjemu primeru.
Varnostne lastnosti, prikazane tukaj, so del standardne komponente HotPDF Component za Delphi in C++Builder; spletna stran izdelka vsebuje celotno referenco o šifriranju, vključno s celotno enumeracijo dovoljenj.