Sicurezza: cifratura, crypto-policy e superficie di firma
In breve
Sezione intitolata “In breve”Il modulo di sicurezza Core applica la cifratura AES-256 ai documenti, sottopone ogni scelta di algoritmo a un contratto crypto-policy ed espone i punti di integrazione usati da un deployment per collegare un servizio di gestione delle chiavi. La protezione effettiva del documento dipende dalla gestione delle chiavi, dalla robustezza della password, dal reader che lo consuma e dall’ambiente di deployment: questa pagina esplicita ciascun confine.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/core:^3Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Il modulo di sicurezza riunisce tre superfici. La prima riguarda la cifratura: il punto d’ingresso setEncryption() sul documento configura il security handler Standard AES-256. La seconda è il gate della crypto-policy: CryptoPolicyInterface decide quale hash, firma, cifrario e robustezza della chiave un deployment consente. La terza è la superficie di firma, richiamata ma non documentata in questa pagina: vedere Firma.
La cifratura usa AES-256 come definito in ISO 32000-2:2020 §7.6. Il percorso predefinito è il security handler Standard V=5 / R=6 con crypt filter AESV3. La file key ha una lunghezza di 32 byte (256 bit), conforme a FIPS 197. Un percorso opt-in aggiunge la cifratura autenticata AES-256-GCM ISO/TS 32003:2023 V=6 / R=7. La pagina di approfondimento documenta entrambi i percorsi: Cifratura.
Il gate della crypto-policy funziona come predicato di negazione o consenso. Core consulta CryptoPolicyInterface prima di qualsiasi operazione di firma, cifratura o hashing. In assenza di una policy impostata, Core consente ogni algoritmo: un valore predefinito aperto, adatto allo sviluppo ma non a un assetto di produzione. Un deployment regolamentato deve impostare una policy esplicita. Contratti / Security Policy documenta la superficie del contratto.
I flag dei permessi sono l’area in cui più spesso si rischia di eccedere nelle affermazioni, perciò questa pagina è esplicita. La bitmask dei permessi è riportata nella voce cifrata /Perms e nel valore /P. Ci si aspetta che un reader conforme rispetti le restrizioni. I flag non sono imposti dalla crittografia. Un processore che ignora i bit può comunque leggere, copiare o modificare il contenuto una volta in possesso della chiave di decifratura. Dichiarare questo limite a qualsiasi parte che faccia affidamento sui flag dei permessi.
La gestione delle chiavi e l’integrazione PKCS#11 sono punti definiti dal contratto. Core fornisce un percorso a chiave locale. Il value object KeyMaterial incapsula una chiave a 256 bit con lunghezza verificata ed evita la divulgazione tramite le sue rappresentazioni string e debug. Il percorso di custodia delle chiavi tramite HSM e PKCS#11 è una funzionalità Enterprise ed è soggetto agli stessi contratti; questa pagina ne indica il punto di integrazione ma non documenta l’implementazione Enterprise.
Superficie API
Sezione intitolata “Superficie API”| Tipo | Genere | Membri principali | Stabilità | Da |
|---|---|---|---|---|
Document::setEncryption() | metodo (concern HasSecurity) | userPassword, ownerPassword, permissions | stabile | 1.0.0 |
Document::useAesGcm() | metodo (concern HasSecurity) | ?bool $enabled — opt-in ISO/TS 32003 V=6/R=7 | stabile | 2.18.0 |
Aes256Encryptor | classe | encrypt(), decrypt(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms() | stabile | 1.0.0 |
Aes256GcmEncryptor | classe | encrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount() | stabile | 2.18.0 |
KeyMaterial | final readonly class | generate(), exposeKey(), fingerprint() | stabile | 2.18.0 |
CryptoPolicyInterface | interfaccia | isHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName() | stabile | 1.9.0 |
Config::withCryptoPolicy() | metodo | CryptoPolicyInterface $policy | stabile | 1.9.0 |
CryptoCapabilities | final class | hasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile() | stabile | 2.0.0 |
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Encrypted Document — Restricted Permissions');
// Call setEncryption() BEFORE addPage().// Permission bit 3 (value 4) = printing allowed; all other operations denied.$doc->setEncryption( userPassword: 'demo', ownerPassword: 'admin', permissions: 4,);
$doc->addPage();$doc->setFont('helvetica', 'B', 20);$doc->cell(0, 14, 'Encrypted PDF Document', newLine: true);
$doc->save(__DIR__ . '/output/22-protection.pdf');La user password permette di aprire il documento. La owner password concede l’accesso completo. I flag dei permessi vincolano soltanto un reader conforme.
Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;use NextPDF\Core\Document;use Psr\Log\LoggerInterface;
final readonly class PolicyGatedEncryption{ public function __construct( private CryptoPolicyInterface $cryptoPolicy, private LoggerInterface $logger, ) {}
/** * Encrypt only when the active policy permits AES-256-CBC. * * @param non-empty-string $userPassword Opens the document. * @param non-empty-string $ownerPassword Grants full access. */ public function protect( Document $doc, string $userPassword, string $ownerPassword, int $permissions, ): void { if (!$this->cryptoPolicy->isEncryptionAlgorithmAllowed('aes-256-cbc')) { $this->logger->error('Encryption refused by crypto policy', [ 'policy' => $this->cryptoPolicy->getName(), ]);
throw new \RuntimeException('AES-256-CBC denied by the active crypto policy.'); }
$doc->setEncryption($userPassword, $ownerPassword, $permissions);
$this->logger->info('Document encrypted', [ 'policy' => $this->cryptoPolicy->getName(), 'algorithm' => 'aes-256-cbc', ]); }}Il gate consulta la policy prima della cifratura, registra il nome della policy nell’audit trail e rifiuta l’operazione con un’eccezione specifica quando la policy nega il cifrario.
Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Chiamare
setEncryption()prima diaddPage(). Una chiamata successiva non cifra retroattivamente il contenuto già emesso dal writer. - La modalità PDF/A e la cifratura si escludono a vicenda. ISO 19005 vieta la chiave
Encryptdel trailer in ogni variante PDF/A, perciòsetEncryption()euseAesGcm()sollevano un’eccezione quando è attivo un manager PDF/A. - Una owner password vuota fa fallback sulla user password all’interno di
setEncryption(). Un documento con un’unica password condivisa concede a chi detiene la user password un accesso di livello owner. CryptoPolicyInterfaceconsente ogni algoritmo quando non viene iniettata alcuna policy. Considerare il valore predefinito aperto come comodità per lo sviluppo e impostare una policy esplicita in qualsiasi deployment regolamentato.- I flag dei permessi hanno carattere indicativo per il reader. Non descriverli come un controllo di accesso che un processore ostile non possa aggirare.
Prestazioni
Sezione intitolata “Prestazioni”setEncryption() esegue una routine iterativa di derivazione della chiave (Algorithm 2.B, revision 6) al momento della build del documento. Il costo è limitato e costante per documento, non proporzionale al numero di pagine. La cifratura per oggetto è un’operazione AES per ogni flusso o stringa. Il percorso opt-in AES-256-GCM aggiunge un overhead di 28 byte per oggetto (IV di 12 byte più tag di 16 byte) ed esegue lo streaming dei contenuti di grandi dimensioni in chunk da 16 MiB. Questo mantiene la fase di streaming al di sotto del picco documentato di 64 MB. Il performance_budget di 1500 ms wall e 64 MB di picco è dominato dal rendering del documento, non dalla fase di cifratura.
Note di sicurezza
Sezione intitolata “Note di sicurezza”Il threat model è esplicito. Il downgrade dell’algoritmo è mitigato dal gate della crypto-policy, che rifiuta cifrari deboli, hash deboli e chiavi corte prima di qualsiasi operazione. Il motore non sostituisce silenziosamente una primitiva con una più debole quando quella richiesta è assente: solleva un’eccezione affinché l’operatore possa intervenire. La divulgazione della chiave tramite logging è mitigata da KeyMaterial, le cui rappresentazioni string e debug oscurano i byte ed espongono solo un fingerprint non reversibile. La manomissione del ciphertext viene rilevata solo sul percorso opt-in AES-256-GCM, dove il tag di autenticazione viene verificato e una mancata corrispondenza solleva un’eccezione anziché restituire il plaintext. Il percorso predefinito AES-256-CBC garantisce solo la riservatezza e da solo non rileva le modifiche. Il riutilizzo dell’IV sul percorso GCM è mitigato da un contatore monotono più un collision set come difesa in profondità, conforme al requisito di IV univoco di NIST SP 800-38D §8.
Anche il confine è esplicito. La cifratura AES-256 è applicata come definito in ISO 32000-2:2020 §7.6. La protezione effettiva dipende dalla robustezza della password, dalla gestione delle chiavi, dall’ambiente di deployment e dal reader che lo consuma. I flag dei permessi sono rispettati dai reader conformi e non sono imposti a livello crittografico. La probe della modalità FIPS segnala se la build OpenSSL dell’host ha caricato un provider FIPS. La libreria opera in una modalità compatibile con FIPS quando l’host fornisce un modulo validato, senza certificare a sua volta alcun modulo. NIST SP 800-57 Part 1 §4 inquadra la durata della chiave e il cryptoperiod come responsabilità del deployment. Core espone i controlli, ma spetta al deployment impostare la policy di rotazione.
Residenza dei dati e mitigazioni dei PII
Sezione intitolata “Residenza dei dati e mitigazioni dei PII”La superficie di cifratura non trasmette i byte del documento al di fuori dell’host. La derivazione della chiave, la cifratura e la decifratura vengono eseguite in-process. Il percorso opt-in GCM indicizza in memoria un IV-collision set basato su un fingerprint della chiave non reversibile, non sui byte della chiave. Il modulo di sicurezza non scrive su disco alcun valore di password o di chiave. Un deployment che instrada le chiavi attraverso un servizio esterno di gestione delle chiavi è responsabile della residenza di tale servizio.
Telemetria sicura e pulizia dei log
Sezione intitolata “Telemetria sicura e pulizia dei log”KeyMaterial::__toString() e __debugInfo() restituiscono un placeholder oscurato, perciò un log accidentale di un oggetto chiave produce un fingerprint, non i byte della chiave. Le password passate a setEncryption() sono marcate con l’attributo #[\SensitiveParameter], che le oscura da uno stack trace. Gli identificatori adatti all’audit di un’operazione crittografica sono il nome della policy fornito da CryptoPolicyInterface::getName() e il fingerprint della chiave di 8 caratteri: registrare questi valori, mai la chiave o la password.
Threat model
Sezione intitolata “Threat model”| Minaccia | Mitigazione in Core | Confine residuo |
|---|---|---|
| Downgrade dell’algoritmo / sostituzione con cifrario debole | Gate della crypto-policy; nessuna degradazione silenziosa (solleva UnsupportedAlgorithmException) | Efficace solo quando viene iniettata una policy |
| Divulgazione della chiave tramite i log | KeyMaterial con oscuramento; #[\SensitiveParameter] sulle password | Un chiamante che passa exposeKey() a un logger vanifica questa misura |
| Manomissione del ciphertext | Verifica del tag GCM sul percorso opt-in | Il percorso predefinito CBC garantisce solo la riservatezza |
| Riutilizzo dell’IV (GCM) | Contatore monotono più collision set; il rollover viene rifiutato | — |
| Bypass dei flag dei permessi | Nessuna — i flag hanno carattere indicativo | Un reader non conforme ignora i flag |
| Brute-force su una password debole | SASLprep più la derivazione iterata della chiave aumentano il costo | Una password debole rimane il rischio dominante |
Comportamento in modalità FIPS
Sezione intitolata “Comportamento in modalità FIPS”Core non è un modulo crittografico validato FIPS e non è certificato FIPS. CryptoCapabilities::detectFipsMode() è una probe runtime best-effort: legge un override dell’operatore, poi l’elenco dei provider OpenSSL, poi la chiamata FIPS-mode legacy e segnala active, absent o indeterminate. assertFipsAvailableForProfile() fallisce in modo fail-closed quando viene selezionato un profilo FIPS su un host che non dimostra un provider FIPS. La libreria opera in una modalità compatibile con FIPS quando è configurata su una build OpenSSL dell’host che ha caricato un provider validato FIPS. Un assetto FIPS validato e certificato riguarda l’edizione Enterprise; vedere la documentazione Enterprise.
Conformità
Sezione intitolata “Conformità”| Affermazione | Standard | Clausola | Evidenza |
|---|---|---|---|
| Il percorso GCM mantiene ogni IV univoco per invocazione, in conformità con il requisito di univocità dello standard. | NIST SP 800-38D | §8.2.1 | |
| La durata della chiave e il cryptoperiod sono una responsabilità del deployment per cui Core espone controlli. | NIST SP 800-57 Part 1 Rev. 5 | §4 | |
| La file key AES è di 256 bit, conforme alla lunghezza della chiave dello standard. | FIPS 197 | §4.2.1 | |
| La generazione di chiavi residenti su token è il punto di integrazione per un key store esterno. | OASIS PKCS#11 v3.1 | C_GenerateKey |
ISO 32000-2:2020 §7.6 è la base normativa per il security handler Standard. Il suo testo è soggetto a restrizioni di licenza ed è qui parafrasato, mai citato testualmente; la clausola è citata per numero. Ogni punto sopra è parafrasato dallo standard citato.
Contesto commerciale
Sezione intitolata “Contesto commerciale”Core definisce e stabilizza il contratto crypto-policy, fornisce il percorso di cifratura AES-256 e mette a disposizione una superficie a chiave locale. L’edizione Enterprise fornisce un percorso di custodia delle chiavi HSM/PKCS#11 e un profilo crypto-policy in modalità FIPS tramite lo stesso CryptoPolicyInterface. La superficie del contratto è identica tra le edizioni; la differenza sta nell’implementazione della policy e nel backend di custodia delle chiavi che un deployment inietta.
Vedere anche
Sezione intitolata “Vedere anche”- Sicurezza / Cifratura — il riferimento approfondito su AES-256 e AES-256-GCM.
- Contratti / Security Policy — i contratti crypto-policy e resource-policy.
- Sicurezza / Firma — firme PAdES, CMS e timestamp.
- Audit — logging di audit del nome della policy e delle operazioni.
- Conformità — interazione di PDF/A con la cifratura.