Przejdź do głównej zawartości

Bezpieczeństwo: szyfrowanie, polityka kryptograficzna i obszar podpisywania

Moduł bezpieczeństwa Core stosuje 256-bitowe szyfrowanie dokumentów w standardzie Advanced Encryption Standard (AES-256), przepuszcza każdy wybór algorytmu przez kontrakt polityki kryptograficznej i udostępnia punkty integracji dla usługi zarządzania kluczami zarządzanej po stronie wdrożenia. Skuteczna ochrona dokumentu zależy od obsługi kluczy, siły hasła, czytnika, który odbiera dokument, oraz środowiska wdrożeniowego. Ta strona jasno wyznacza te granice.

Okno terminala
composer require nextpdf/core:^3

Moduł bezpieczeństwa obejmuje trzy obszary. Obszar szyfrowania używa punktu wejścia dokumentu setEncryption() do skonfigurowania standardowej procedury obsługi zabezpieczeń AES-256. Bramka polityki kryptograficznej używa CryptoPolicyInterface, aby określić, które funkcje skrótu, podpisy, szyfry i siły klucza dopuszcza dane wdrożenie. Obszar podpisywania jest tu tylko wspomniany, a udokumentowano go osobno; zobacz Podpisywanie.

Szyfrowanie korzysta z AES-256 zgodnie z definicją w ISO 32000-2:2020 §7.6. Domyślnie używana jest standardowa procedura obsługi zabezpieczeń V=5 / R=6 z filtrem szyfrującym AESV3. Klucz pliku ma 32 bajty (256 bitów), co odpowiada Federal Information Processing Standards (FIPS) 197. Opcjonalnie włączana ścieżka dodaje uwierzytelnione szyfrowanie ISO/TS 32003:2023 V=6 / R=7 AES-256 w trybie Galois/Counter Mode (AES-256-GCM). Szczegółowa strona opisuje obie ścieżki: Szyfrowanie.

Bramka polityki kryptograficznej ma postać predykatu, który odmawia albo zezwala. Core odpytuje CryptoPolicyInterface przed każdym krokiem podpisywania, szyfrowania lub obliczania skrótu. Jeśli nie ustawiono żadnej polityki, Core zezwala na każdy algorytm. Ta otwarta wartość domyślna nadaje się do prac programistycznych, a nie do produkcji. Wdrożenie podlegające regulacjom musi ustawić jawną politykę. Kontrakty / Polityka bezpieczeństwa dokumentuje interfejs kontraktu.

Flagi uprawnień są najczęstszym źródłem zbyt daleko idących deklaracji, dlatego ta strona mówi o nich wprost. Maska bitowa uprawnień jest przechowywana w zaszyfrowanym wpisie /Perms oraz w wartości /P. Od czytnika zgodnego ze specyfikacją oczekuje się respektowania tych ograniczeń. Flagi nie są egzekwowane kryptograficznie. Procesor, który ignoruje te bity, może mimo to odczytać, skopiować lub zmodyfikować treść po uzyskaniu klucza deszyfrującego. Komunikuj to ograniczenie każdej stronie, która polega na flagach uprawnień.

Zarządzanie kluczami oraz integracja Public-Key Cryptography Standards #11 (PKCS#11) są punktami kontraktowymi. Core dostarcza ścieżkę klucza lokalnego. Obiekt wartości KeyMaterial opakowuje 256-bitowy klucz o sprawdzonej długości i chroni przed ujawnieniem w tekstowych oraz debugowych danych wyjściowych. Ścieżka powierniczego przechowywania kluczy w sprzętowym module zabezpieczeń (HSM)/PKCS#11 to funkcja Enterprise objęta tymi samymi kontraktami; ta strona wskazuje punkt integracji, ale nie dokumentuje implementacji Enterprise.

TypRodzajKluczowe składoweStabilnośćOd wersji
Document::setEncryption()metoda (obszar HasSecurity)userPassword, ownerPassword, permissionsstabilne1.0.0
Document::useAesGcm()metoda (obszar HasSecurity)?bool $enabled — opcjonalnie włączane ISO/TS 32003 V=6/R=7stabilne2.18.0
Aes256Encryptorklasaencrypt(), decrypt(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms()stabilne1.0.0
Aes256GcmEncryptorklasaencrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount()stabilne2.18.0
KeyMaterialfinal readonly classgenerate(), exposeKey(), fingerprint()stabilne2.18.0
CryptoPolicyInterfaceinterfejsisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()stabilne1.9.0
Config::withCryptoPolicy()metodaCryptoPolicyInterface $policystabilne1.9.0
CryptoCapabilitiesfinal classhasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile()stabilne2.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');

Hasło użytkownika otwiera dokument. Hasło właściciela zapewnia pełny dostęp. Flagi uprawnień ograniczają wyłącznie czytnik zgodny ze specyfikacją.

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',
]);
}
}

Bramka odpytuje politykę przed szyfrowaniem, zapisuje nazwę polityki w śladzie audytu i zgłasza konkretny wyjątek, gdy polityka odrzuca dany szyfr.

  • Wywołaj setEncryption() przed addPage(). Późniejsze wywołanie nie szyfruje wstecznie treści, które moduł zapisujący już wyemitował.
  • Tryb PDF/A i szyfrowanie wzajemnie się wykluczają. ISO 19005 zabrania klucza Encrypt w trailerze w każdej odmianie PDF/A, dlatego setEncryption() i useAesGcm() zgłaszają wyjątek, gdy aktywny jest menedżer PDF/A.
  • Wewnątrz setEncryption() puste hasło właściciela zostaje zastąpione hasłem użytkownika. Dokument z jednym współdzielonym hasłem daje posiadaczowi hasła użytkownika dostęp na poziomie właściciela.
  • Gdy nie wstrzyknięto żadnej polityki, CryptoPolicyInterface zezwala na każdy algorytm. Otwartą wartość domyślną traktuj jako udogodnienie programistyczne i ustaw jawną politykę w każdym wdrożeniu podlegającym regulacjom.
  • Flagi uprawnień są dla czytnika zaleceniami. Nie opisuj ich jako kontroli dostępu, której wrogi procesor nie może obejść.

setEncryption() uruchamia iteracyjną procedurę wyprowadzania klucza (Algorytm 2.B, wersja 6) podczas budowania dokumentu. Koszt jest ograniczony i stały dla dokumentu; nie skaluje się z liczbą stron. Podczas szyfrowania pojedynczych obiektów wykonywana jest jedna operacja AES na strumień lub łańcuch znaków. Opcjonalnie włączana ścieżka AES-256-GCM dodaje 28 bajtów narzutu na obiekt (12-bajtowy wektor inicjujący (IV) plus 16-bajtowy znacznik) i przetwarza strumieniowo dużą treść w blokach po 16 MiB. Dzięki temu przetwarzanie strumieniowe pozostaje poniżej udokumentowanego szczytowego zużycia 64 MB. W budżecie performance_budget wynoszącym 1500 ms czasu rzeczywistego i 64 MB szczytu dominuje renderowanie dokumentu, a nie szyfrowanie.

Model zagrożeń jest jasno określony. Bramka polityki kryptograficznej ogranicza ryzyko obniżenia poziomu algorytmu, odrzucając słabe szyfry, słabe funkcje skrótu i krótkie klucze przed każdą operacją. Silnik nie zastępuje po cichu niedostępnego prymitywu słabszym; zgłasza wyjątek, aby operator mógł zareagować. KeyMaterial ogranicza ryzyko ujawnienia klucza przez dzienniki: jego reprezentacje tekstowa i debugowa maskują bajty i ujawniają wyłącznie nieodwracalny odcisk. Manipulacja szyfrogramem jest wykrywana wyłącznie na opcjonalnie włączanej ścieżce AES-256-GCM, gdzie znacznik uwierzytelniający jest weryfikowany, a niezgodność powoduje zgłoszenie wyjątku zamiast zwrócenia tekstu jawnego. Domyślna ścieżka AES-256 Cipher Block Chaining (AES-256-CBC) zapewnia wyłącznie poufność i sama z siebie nie wykrywa modyfikacji. Na ścieżce GCM ponowne użycie IV jest ograniczane przez monotoniczny licznik oraz zestaw kolizyjny jako mechanizm obrony warstwowej, zgodnie z wymogiem unikalnego IV w NIST SP 800-38D §8.

Granice są równie jasno określone. Szyfrowanie AES-256 jest stosowane zgodnie z definicją w ISO 32000-2:2020 §7.6. Skuteczna ochrona zależy od siły hasła, zarządzania kluczami, środowiska wdrożeniowego oraz czytnika, który odbiera dokument. Czytniki zgodne ze specyfikacją respektują flagi uprawnień, ale kryptografia ich nie egzekwuje. Sonda trybu FIPS raportuje, czy kompilacja OpenSSL na hoście wczytała dostawcę FIPS. Biblioteka działa w trybie zgodnym z FIPS, gdy host udostępnia zwalidowany moduł; nie certyfikuje żadnego modułu. NIST SP 800-57 Part 1 §4 traktuje czas życia klucza i okres kryptograficzny jako obowiązki wdrożenia. Core udostępnia mechanizmy sterujące, a wdrożenie ustala politykę rotacji.

Obszar szyfrowania nie przesyła bajtów dokumentu poza hosta, w tym żadnych zawartych w nich danych umożliwiających identyfikację osoby (PII). Wyprowadzanie klucza, szyfrowanie i deszyfrowanie odbywają się w obrębie procesu. Opcjonalnie włączana ścieżka GCM indeksuje przechowywany w pamięci zestaw kolizji IV za pomocą nieodwracalnego odcisku klucza, a nie bajtów klucza. Moduł bezpieczeństwa nie zapisuje na dysku żadnego hasła ani wartości klucza. Wdrożenie kierujące klucze przez zewnętrzną usługę zarządzania kluczami odpowiada za rezydencję tej usługi.

KeyMaterial::__toString() oraz __debugInfo() zwracają zamaskowany symbol zastępczy, więc przypadkowe zapisanie obiektu klucza w dzienniku skutkuje zapisaniem odcisku, a nie bajtów klucza. Hasła przekazane do setEncryption() mają atrybut #[\SensitiveParameter], który maskuje je w śladzie stosu. W audytach jako identyfikatorów operacji kryptograficznych używaj nazwy polityki z CryptoPolicyInterface::getName() oraz 8-znakowego odcisku klucza. Rejestruj te wartości, nigdy klucza ani hasła.

ZagrożenieŚrodek ograniczający w CoreGranica resztkowa
Obniżenie poziomu algorytmu / podstawienie słabego szyfruBramka polityki kryptograficznej; brak cichego obniżenia poziomu (zgłasza UnsupportedAlgorithmException)Skuteczne tylko wtedy, gdy wstrzyknięto politykę
Ujawnienie klucza w dziennikachMaskowanie KeyMaterial; #[\SensitiveParameter] na hasłachWywołujący, który przekaże exposeKey() do rejestratora, niweczy ten mechanizm
Manipulacja szyfrogramemWeryfikacja znacznika GCM na ścieżce włączanej opcjonalnieDomyślna ścieżka CBC zapewnia wyłącznie poufność
Ponowne użycie IV (GCM)Monotoniczny licznik plus zestaw kolizyjny; przepełnienie powoduje odmowę
Obejście flag uprawnieńBrak; flagi mają charakter zaleceńCzytnik niezgodny ze specyfikacją ignoruje flagi
Atak siłowy na słabe hasłoSASLprep oraz iteracyjne wyprowadzanie klucza podnoszą kosztSłabe hasło pozostaje dominującym ryzykiem

Core nie jest modułem kryptograficznym zwalidowanym pod kątem FIPS ani nie posiada certyfikatu FIPS. CryptoCapabilities::detectFipsMode() to sonda działająca w czasie wykonania na zasadzie najlepszych starań: odczytuje nadpisanie ustawione przez operatora, następnie listę dostawców OpenSSL, a potem starsze wywołanie trybu FIPS, i raportuje stan aktywny, nieobecny lub nieokreślony. assertFipsAvailableForProfile() zawodzi w sposób bezpieczny (fail-closed), gdy wybrano profil FIPS na hoście, który nie może potwierdzić dostawcy FIPS. Biblioteka działa w trybie zgodnym z FIPS, gdy jest skonfigurowana z kompilacją OpenSSL na hoście, która wczytała dostawcę zwalidowanego pod kątem FIPS. Zwalidowany i certyfikowany status FIPS należy do Enterprise; zobacz dokumentację Enterprise.

DeklaracjaNormaKlauzulaDowód
Ścieżka GCM utrzymuje unikalność każdego IV dla danego wywołania, zgodnie z wymogiem unikalności określonym w normie.NIST SP 800-38D§8.2.1
Core udostępnia mechanizmy sterujące czasem życia klucza i okresem kryptograficznym; polityka należy do wdrożenia.NIST SP 800-57 Part 1 Rev. 5§4
Klucz pliku AES ma 256 bitów, co odpowiada długości klucza określonej w normie.FIPS 197§4.2.1
Generowanie klucza rezydującego w tokenie jest punktem integracji z zewnętrznym magazynem kluczy.OASIS PKCS#11 v3.1C_GenerateKey

ISO 32000-2:2020 §7.6 stanowi normatywną podstawę standardowej procedury obsługi zabezpieczeń. Jej tekst podlega ograniczeniom licencyjnym i tutaj jest parafrazowany, nigdy cytowany; ta strona przywołuje klauzulę przez numer. Każdy z powyższych punktów jest parafrazą przywołanej normy.

Core definiuje i stabilizuje kontrakt polityki kryptograficznej, dostarcza ścieżkę szyfrowania AES-256 oraz udostępnia lokalny interfejs klucza. Edycja Enterprise dostarcza ścieżkę powierniczego przechowywania kluczy HSM/PKCS#11 oraz profil polityki kryptograficznej w trybie FIPS za tym samym CryptoPolicyInterface. Interfejs kontraktu jest identyczny we wszystkich edycjach; wdrożenie wstrzykuje inną implementację polityki i zaplecze powierniczego przechowywania kluczy.