Zum Inhalt springen

Sicherheit: Verschlüsselung, Crypto-Policy und Signaturoberfläche

Das Core-Sicherheitsmodul setzt AES-256-Dokumentverschlüsselung ein, prüft jede Algorithmuswahl über einen Crypto-Policy-Vertrag und stellt Integrationspunkte bereit, über die ein Deployment einen Schlüsselverwaltungsdienst anbinden kann. Wirksamer Dokumentschutz hängt von der Schlüsselhandhabung, der Passwortstärke, dem verarbeitenden Reader und der Deployment-Umgebung ab — diese Seite benennt jede Grenze klar.

Terminal-Fenster
composer require nextpdf/core:^3

Das Sicherheitsmodul stellt drei Oberflächen bereit. Die erste ist die Verschlüsselung: Der Einstiegspunkt setEncryption() am Dokument konfiguriert den AES-256-Standard-Sicherheits-Handler. Die zweite ist das Crypto-Policy-Gate: CryptoPolicyInterface entscheidet, welche Hash-, Signatur- und Verschlüsselungsalgorithmen sowie welche Schlüsselstärken ein Deployment zulässt. Die dritte ist die Signaturoberfläche, die diese Seite nur referenziert, aber nicht dokumentiert — siehe Signatur.

Die Verschlüsselung nutzt AES-256 gemäß ISO 32000-2:2020 §7.6. Der Standardpfad verwendet den Standard-Sicherheits-Handler V=5 / R=6 mit dem AESV3-Crypt-Filter. Die Bytelänge des Dateischlüssels beträgt 32 Byte (256 Bit) und entspricht FIPS 197. Optional ergänzt ein Pfad die authentifizierte Verschlüsselung ISO/TS 32003:2023 V=6 / R=7 AES-256-GCM. Die Detailseite dokumentiert beide Varianten: Verschlüsselung.

Das Crypto-Policy-Gate ist ein Prädikat, das verweigert oder zulässt. Core konsultiert CryptoPolicyInterface vor jedem Signatur-, Verschlüsselungs- oder Hashing-Schritt. Ohne gesetzte Policy lässt Core jeden Algorithmus zu — eine offene Voreinstellung, die für die Entwicklung geeignet ist, nicht für eine Produktionsumgebung. Ein reguliertes Deployment muss eine explizite Policy setzen. Contracts / Security Policy dokumentiert die Vertragsoberfläche.

Berechtigungsflags sind der häufigste Anlass für überzogene Aussagen, deshalb ist diese Seite hier ausdrücklich. Die Berechtigungsbitmaske wird im verschlüsselten Eintrag /Perms und im Wert /P transportiert. Von einem konformen Reader wird erwartet, dass er die Einschränkungen einhält. Die Flags werden nicht kryptografisch erzwungen. Ein Prozessor, der die Bits ignoriert, kann den Inhalt weiterhin lesen, kopieren oder verändern, sobald er den Entschlüsselungsschlüssel hat. Benennen Sie diese Grenze gegenüber jeder Partei, die sich auf Berechtigungsflags verlässt.

Schlüsselverwaltung und PKCS#11-Integration sind vertraglich definierte Integrationspunkte. Core liefert einen Pfad für lokale Schlüssel mit. Das Value Object KeyMaterial umschließt einen längengeprüften 256-Bit-Schlüssel und widersteht der Offenlegung über seine String- und Debug-Darstellungen. Der HSM- und PKCS#11-Schlüsselverwahrungspfad ist eine Enterprise-Fähigkeit, die hinter denselben Verträgen abgesichert ist; diese Seite benennt den Integrationspunkt, dokumentiert aber nicht die Enterprise-Implementierung.

TypArtWichtige MitgliederStabilitätSeit
Document::setEncryption()Methode (Concern HasSecurity)userPassword, ownerPassword, permissionsstable1.0.0
Document::useAesGcm()Methode (Concern HasSecurity)?bool $enabled — optional ISO/TS 32003 V=6/R=7stable2.18.0
Aes256EncryptorKlasseencrypt(), decrypt(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms()stable1.0.0
Aes256GcmEncryptorKlasseencrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount()stable2.18.0
KeyMaterialfinal readonly classgenerate(), exposeKey(), fingerprint()stable2.18.0
CryptoPolicyInterfaceinterfaceisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()stable1.9.0
Config::withCryptoPolicy()MethodeCryptoPolicyInterface $policystable1.9.0
CryptoCapabilitiesfinal classhasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile()stable2.0.0
examples/22-protection.php
<?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');

Das Benutzerkennwort öffnet das Dokument. Das Eigentümerkennwort gewährt vollen Zugriff. Die Berechtigungsflags beschränken nur einen konformen Reader.

examples/security/policy-gated-encryption.php
<?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',
]);
}
}

Das Gate prüft vor der Verschlüsselung die Policy, protokolliert den Policy-Namen für den Audit-Trail und bricht mit einer spezifischen Exception ab, wenn die Policy die Chiffre verweigert.

  • Rufen Sie setEncryption() vor addPage() auf. Ein späterer Aufruf verschlüsselt Inhalt, den der Writer bereits ausgegeben hat, nicht nachträglich.
  • PDF/A-Modus und Verschlüsselung schließen sich gegenseitig aus. ISO 19005 verbietet den Trailer-Schlüssel Encrypt in jeder PDF/A-Variante, daher lösen setEncryption() und useAesGcm() eine Exception aus, wenn ein PDF/A-Manager aktiv ist.
  • Ein leeres Eigentümerkennwort greift innerhalb von setEncryption() auf das Benutzerkennwort zurück. Ein Dokument mit einem einzigen gemeinsamen Kennwort gibt dem Inhaber des Benutzerkennworts Zugriff auf Eigentümerebene.
  • CryptoPolicyInterface lässt jeden Algorithmus zu, wenn keine Policy injiziert ist. Behandeln Sie die offene Voreinstellung als Entwicklungserleichterung und setzen Sie in jedem regulierten Deployment eine explizite Policy.
  • Berechtigungsflags sind für den Reader beratend. Beschreiben Sie sie nicht als Zugriffskontrolle, die ein feindlicher Prozessor nicht umgehen kann.

setEncryption() führt während des Dokument-Builds eine iterierte Schlüsselableitungsroutine aus (Algorithmus 2.B, Revision 6). Der Aufwand ist begrenzt und pro Dokument konstant, nicht proportional zur Seitenzahl. Bei der Verschlüsselung fällt pro Objekt eine AES-Operation pro Stream oder String an. Der optionale AES-256-GCM-Pfad fügt pro Objekt einen Overhead von 28 Byte hinzu (12-Byte-IV plus 16-Byte-Tag) und streamt große Inhalte in 16-MiB-Blöcken. Das hält den Streaming-Durchlauf unter dem dokumentierten Spitzenwert von 64 MB. Das performance_budget von 1500 ms Wall-Zeit und 64 MB Spitzenverbrauch wird vom Dokument-Rendering dominiert, nicht vom Verschlüsselungsschritt.

Das Bedrohungsmodell ist explizit. Algorithmus-Downgrade wird durch das Crypto-Policy-Gate gemildert, das schwache Chiffren, schwache Hashes und kurze Schlüssel vor jeder Operation verweigert. Die Engine ersetzt ein angefordertes Primitiv nicht stillschweigend durch ein schwächeres, wenn es fehlt — sie löst eine Exception aus, damit der Betreiber handeln kann. Schlüssel-Offenlegung durch Logging wird durch KeyMaterial gemildert, dessen String- und Debug-Darstellungen die Bytes schwärzen und nur einen nicht umkehrbaren Fingerabdruck offenlegen. Chiffretext-Manipulation wird nur auf dem optionalen AES-256-GCM-Pfad erkannt, wo das Authentifizierungs-Tag verifiziert wird und eine Abweichung eine Exception auslöst, statt Klartext zurückzugeben. Der AES-256-CBC-Standardpfad ist ausschließlich auf Vertraulichkeit ausgelegt und erkennt eine Veränderung nicht von selbst. IV-Wiederverwendung auf dem GCM-Pfad wird durch einen monotonen Zähler plus eine Defence-in-Depth-Kollisionsmenge gemildert, im Einklang mit der Anforderung eindeutiger IVs in NIST SP 800-38D §8.

Die Grenze ist ebenso explizit. AES-256-Verschlüsselung wird gemäß ISO 32000-2:2020 §7.6 angewendet. Wirksamer Schutz hängt von der Passwortstärke, der Schlüsselverwaltung, der Deployment-Umgebung und dem verarbeitenden Reader ab. Berechtigungsflags werden von konformen Readern eingehalten und nicht kryptografisch erzwungen. Die FIPS-Modus-Sonde meldet, ob der OpenSSL-Build des Hosts einen FIPS-Provider geladen hat. Die Bibliothek arbeitet in einem FIPS-kompatiblen Modus, wenn der Host ein validiertes Modul bereitstellt, zertifiziert selbst jedoch kein Modul. NIST SP 800-57 Part 1 §4 fasst Schlüssellebensdauer und Kryptoperiode als Verantwortung des Deployments auf. Core stellt die Steuerungen bereit, doch ein Deployment legt die Rotationsrichtlinie fest.

Die Verschlüsselungsoberfläche überträgt keine Dokumentbytes außerhalb des Hosts. Schlüsselableitung, Verschlüsselung und Entschlüsselung laufen prozessintern. Der optionale GCM-Pfad indiziert eine In-Memory-IV-Kollisionsmenge über einen nicht umkehrbaren Schlüssel-Fingerabdruck, nicht über Schlüsselbytes. Das Sicherheitsmodul schreibt keine Passwort- oder Schlüsselwerte auf die Festplatte. Ein Deployment, das Schlüssel über einen externen Schlüsselverwaltungsdienst leitet, ist für die Datenresidenz dieses Dienstes verantwortlich.

KeyMaterial::__toString() und __debugInfo() geben einen geschwärzten Platzhalter zurück, sodass ein versehentlich protokolliertes Schlüsselobjekt einen Fingerabdruck liefert, keine Schlüsselbytes. Passwörter, die an setEncryption() übergeben werden, tragen das Attribut #[\SensitiveParameter], das sie aus einem Stack-Trace schwärzt. Der auditfreundliche Bezeichner für eine Crypto-Operation ist der Policy-Name aus CryptoPolicyInterface::getName() und der 8-stellige Schlüssel-Fingerabdruck — protokollieren Sie diese Werte, niemals den Schlüssel oder das Passwort.

BedrohungMinderung in CoreVerbleibende Grenze
Algorithmus-Downgrade / Ersatz durch schwache ChiffreCrypto-Policy-Gate; keine stille Verschlechterung (löst UnsupportedAlgorithmException aus)Nur wirksam, wenn eine Policy injiziert ist
Schlüssel-Offenlegung über LogsKeyMaterial-Schwärzung; #[\SensitiveParameter] auf PasswörternEin Aufrufer, der exposeKey() an einen Logger übergibt, setzt diese Minderung außer Kraft
Chiffretext-ManipulationGCM-Tag-Verifizierung auf dem optionalen PfadDer Standard-CBC-Pfad ist ausschließlich auf Vertraulichkeit ausgelegt
IV-Wiederverwendung (GCM)Monotoner Zähler plus Kollisionsmenge; Überlauf verweigert
Umgehung von BerechtigungsflagsKeine — Flags sind beratendEin nicht konformer Reader ignoriert die Flags
Brute-Force auf einem schwachen PasswortSASLprep plus iterierte Schlüsselableitung erhöht die KostenEin schwaches Passwort bleibt das dominierende Risiko

Core ist kein FIPS-validiertes kryptografisches Modul und nicht FIPS-zertifiziert. CryptoCapabilities::detectFipsMode() ist eine Best-Effort-Laufzeitsonde: Sie liest einen Betreiber-Override, dann die OpenSSL-Provider-Liste, dann den Legacy-FIPS-Modus-Aufruf und meldet active, absent oder indeterminate. assertFipsAvailableForProfile() schlägt sicher fehl, wenn ein FIPS-Profil auf einem Host gewählt wird, der keinen FIPS-Provider nachweist. Die Bibliothek arbeitet in einem FIPS-kompatiblen Modus, wenn sie gegen einen OpenSSL-Build des Hosts konfiguriert ist, der einen FIPS-validierten Provider geladen hat. Eine validierte, zertifizierte FIPS-Haltung ist ein Enterprise-Anliegen; siehe die Enterprise-Dokumentation.

BehauptungStandardKlauselNachweis
Der GCM-Pfad stellt die Eindeutigkeit jedes IV pro Aufruf sicher, im Einklang mit der Eindeutigkeitsanforderung des Standards.NIST SP 800-38D§8.2.1
Schlüssellebensdauer und Kryptoperiode sind eine Verantwortung des Deployments, für die Core Steuerungen bereitstellt.NIST SP 800-57 Part 1 Rev. 5§4
Der AES-Datei-Schlüssel hat 256 Bit und entspricht der Schlüssellänge des Standards.FIPS 197§4.2.1
Token-residente Schlüsselgenerierung ist der Integrationspunkt für einen externen Schlüsselspeicher.OASIS PKCS#11 v3.1C_GenerateKey

ISO 32000-2:2020 §7.6 ist die normative Grundlage für den Standard-Sicherheits-Handler. Sein Text ist lizenzbeschränkt und wird hier paraphrasiert, niemals zitiert; die Klausel wird per Nummer zitiert. Jeder Punkt oben ist aus dem zitierten Standard paraphrasiert.

Core definiert den Crypto-Policy-Vertrag, friert ihn ein, liefert den AES-256-Verschlüsselungspfad und stellt eine Oberfläche für lokale Schlüssel bereit. Die Enterprise-Edition liefert einen HSM-/PKCS#11-Schlüsselverwahrungspfad und ein FIPS-Modus-Crypto-Policy-Profil hinter demselben CryptoPolicyInterface. Die Vertragsoberfläche ist über alle Editionen hinweg identisch; der Unterschied liegt in der Policy-Implementierung und dem Schlüsselverwahrungs-Backend, das ein Deployment injiziert.