跳到內容

安全性:加密、加密政策與簽章介面

Core 安全模組會對文件套用 AES-256 加密,讓每一次演算法選擇都先由加密政策合約(crypto-policy)把關,並提供部署環境串接金鑰管理服務所需的整合點。有效的文件保護取決於金鑰處理、密碼強度、使用端閱讀器與部署環境;本頁會逐項說明這些邊界。

Terminal window
composer require nextpdf/core:^3

安全模組整合三個介面。第一個是加密:文件上的 setEncryption() 進入點會設定 AES-256 Standard 安全處理器。第二個是加密政策閘門:CryptoPolicyInterface 決定部署環境允許哪些雜湊、簽章、密碼演算法與金鑰強度。第三個是簽章介面;本頁僅引用,不在此詳述,請參閱 簽章 一節。

加密採用 ISO 32000-2:2020 §7.6 所定義的 AES-256。預設路徑使用搭配 AESV3 加密過濾器的 V=5/R=6 Standard 安全處理器。檔案金鑰長度為 32 位元組(256 位元),與 FIPS 197 一致。可選用路徑會加上 ISO/TS 32003:2023 V=6/R=7 的 AES-256-GCM 認證加密。深入說明頁面記載了兩者:請參閱 加密 一節。

加密政策閘門是一個用來拒絕或允許的判定式。Core 會在任何簽章、加密或雜湊步驟之前,先諮詢 CryptoPolicyInterface。若未設定任何政策,Core 會允許所有演算法;這是適合開發、但不適合上線的開放預設值。受監管的部署環境必須設定明確的政策。合約/安全政策 一節記載了這個合約介面。

權限旗標最常被過度宣稱其效果,因此本頁特別說明清楚。權限位元遮罩會隨加密後的 /Perms 項目與 /P 值一起傳遞。符合規範的閱讀器應遵守這些限制。這些旗標並非由密碼學強制執行。一旦取得解密金鑰,忽略這些位元的處理器仍可讀取、複製或修改內容。請向任何倚賴權限旗標的一方說明此限制。

金鑰管理與 PKCS#11 整合屬於合約介面。Core 內建一條本機金鑰路徑。KeyMaterial 值物件會包裝一把經過長度檢查的 256 位元金鑰,並防止金鑰在字串與除錯表示中外洩。HSM 與 PKCS#11 金鑰保管路徑是 Enterprise 功能,並受相同合約把關;本頁只點名此整合點,不詳述 Enterprise 實作。

型別種類主要成員穩定度自版本
Document::setEncryption()方法(concern HasSecurityuserPassword, ownerPassword, permissions穩定1.0.0
Document::useAesGcm()方法(concern HasSecurity?bool $enabled — 可選用的 ISO/TS 32003 V=6/R=7穩定2.18.0
Aes256Encryptorclassencrypt(), decrypt(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms()穩定1.0.0
Aes256GcmEncryptorclassencrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount()穩定2.18.0
KeyMaterialfinal readonly classgenerate(), exposeKey(), fingerprint()穩定2.18.0
CryptoPolicyInterfaceinterfaceisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()穩定1.9.0
Config::withCryptoPolicy()方法CryptoPolicyInterface $policy穩定1.9.0
CryptoCapabilitiesfinal classhasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile()穩定2.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');

使用者密碼用來開啟文件。擁有者密碼則授予完整存取權。權限旗標僅約束符合規範的閱讀器。

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

這個閘門會在加密前先諮詢政策,並將政策名稱寫入稽核軌跡;當政策拒絕該密碼演算法時,則以特定例外拒絕執行。

  • 請先呼叫 setEncryption()之後再呼叫 addPage()。較晚的呼叫不會回溯加密寫入器先前已輸出的內容。
  • PDF/A 模式與加密互斥。ISO 19005 在所有 PDF/A 變體中都禁止 Encrypt trailer 鍵,因此當 PDF/A 管理器啟用時,setEncryption()useAesGcm() 會擲出例外。
  • setEncryption() 內部,空白的擁有者密碼會改用使用者密碼。只使用一組共用密碼的文件,會讓持有使用者密碼的人取得擁有者層級的存取權。
  • CryptoPolicyInterface 在未注入任何政策時會允許所有演算法。請把這個開放預設值視為開發便利,並在任何受監管的部署環境中設定明確的政策。
  • 權限旗標對閱讀器來說只是建議性的。請勿把它們描述成連懷有惡意的處理器都無法繞過的存取控制。

setEncryption() 會在文件建構時執行一段迭代式金鑰衍生程序(Algorithm 2.B,第 6 版)。此成本有上限且每份文件固定,不會與頁數成正比。逐物件加密是每個串流或字串一次 AES 運算。可選用的 AES-256-GCM 路徑會為每個物件增加 28 位元組的額外負荷(12 位元組 IV 加上 16 位元組標籤),並以 16 MiB 區塊串流處理大型內容。這讓串流處理過程可維持在已記載的 64 MB 峰值之下。1500 ms 牆鐘時間與 64 MB 峰值的 performance_budget 主要由文件繪製主導,而不是加密步驟。

威脅模型很明確。演算法降級由加密政策閘門緩解;它會在任何運算之前拒絕弱密碼演算法、弱雜湊與短金鑰。當所請求的基元不存在時,引擎不會悄悄改用較弱的基元;它會擲出例外,讓操作者得以採取行動。因記錄而外洩金鑰的風險由 KeyMaterial 緩解,其字串與除錯形式會遮蔽位元組,只揭露一個不可逆的指紋。密文竄改只會在可選用的 AES-256-GCM 路徑上被偵測到;該路徑會驗證認證標籤,不符時擲出例外,而非回傳明文。預設的 AES-256-CBC 路徑僅提供機密性,本身並不偵測內容是否被修改。GCM 路徑上的 IV 重用會透過單調遞增計數器,加上一個作為縱深防禦的碰撞集合來緩解,符合 NIST SP 800-38D §8 對 IV 唯一性的要求。

邊界同樣明確。AES-256 加密依 ISO 32000-2:2020 §7.6 所定義的方式套用。有效保護取決於密碼強度、金鑰管理、部署環境與使用端閱讀器。權限旗標由符合規範的閱讀器遵守,並非由密碼學強制執行。FIPS 模式探測會回報主機的 OpenSSL 組建是否已載入 FIPS 提供者。當主機提供經驗證的模組時,函式庫會以相容於 FIPS 的模式運作,且其本身不會認證任何模組。NIST SP 800-57 Part 1 §4 將金鑰生命週期與加密週期界定為部署環境的責任。Core 提供這些控制項,但輪替政策由部署環境設定。

加密介面不會把文件位元組傳輸到主機之外。金鑰衍生、加密與解密都在行程內執行。可選用的 GCM 路徑會以不可逆的金鑰指紋(而非金鑰位元組)作為記憶體內 IV 碰撞集合的鍵。安全模組不會把任何密碼或金鑰值寫入磁碟。若部署環境透過外部金鑰管理服務轉送金鑰,該服務的資料落地即由該部署環境負責。

KeyMaterial::__toString()__debugInfo() 會回傳一個遮蔽後的佔位字串,因此即使不慎記錄了金鑰物件,記錄到的也只是指紋,而非金鑰位元組。傳入 setEncryption() 的密碼帶有 #[\SensitiveParameter] 屬性,會把它們從堆疊追蹤中遮蔽。加密運算最適合稽核的識別符,是來自 CryptoPolicyInterface::getName() 的政策名稱與 8 字元的金鑰指紋;請記錄這些,絕不要記錄金鑰或密碼。

威脅Core 中的緩解措施殘留邊界
演算法降級/弱密碼替換加密政策閘門;不會悄悄降級(會擲出 UnsupportedAlgorithmException僅在注入政策時才有效
透過日誌外洩金鑰KeyMaterial 遮蔽;在密碼上加 #[\SensitiveParameter] 屬性exposeKey() 傳入記錄器的呼叫端會破壞此防護
密文竄改在可選用的路徑上驗證 GCM 標籤預設的 CBC 路徑僅提供機密性
IV 重用(GCM)單調遞增計數器加上碰撞集合;溢位時拒絕執行
權限旗標繞過無——旗標僅為建議性不符合規範的閱讀器會忽略這些旗標
對弱密碼的暴力破解SASLprep 加上迭代式金鑰衍生提高了破解成本弱密碼仍是最主要的風險

Core 並非經 FIPS 驗證的密碼學模組,也未取得 FIPS 認證。CryptoCapabilities::detectFipsMode() 是一個盡力而為的執行期探測:它會先讀取操作者覆寫值,接著讀取 OpenSSL 提供者清單,再讀取傳統的 FIPS 模式呼叫,並回報啟用、不存在或無法判定。當在無法證明具備 FIPS 提供者的主機上選擇了 FIPS 設定檔時,assertFipsAvailableForProfile() 會失敗關閉(fail closed)。當函式庫設定為對應一個已載入 FIPS 驗證提供者的主機 OpenSSL 組建時,它會以相容於 FIPS 的模式運作。經驗證且已認證的 FIPS 狀態屬於 Enterprise 範疇;請參閱 Enterprise 文件。

主張標準條款佐證
GCM 路徑會讓每次叫用的 IV 都保持唯一,符合該標準的唯一性要求。NIST SP 800-38D(區塊密碼操作模式標準)§8.2.1
金鑰生命週期與加密週期是部署環境的責任,Core 為此提供控制項。NIST SP 800-57 Part 1 Rev. 5(金鑰管理標準)§4
AES 檔案金鑰為 256 位元,與該標準的金鑰長度相符。FIPS 197§4.2.1
權杖駐留式金鑰產生是外部金鑰儲存區的整合點。OASIS PKCS#11 v3.1(密碼權杖介面標準)C_GenerateKey(金鑰產生函式)

ISO 32000-2:2020 §7.6 是 Standard 安全處理器的規範性依據。其文字受授權限制,此處一律改寫,不引用原文;該條款以編號方式引述。上述每一點都改寫自所引述的標準。

Core 定義並凍結加密政策合約,提供 AES-256 加密路徑與本機金鑰介面。Enterprise 版在相同的 CryptoPolicyInterface 之下提供 HSM/PKCS#11 金鑰保管路徑,以及 FIPS 模式的加密政策設定檔。合約介面在各版本之間完全相同;差異在於部署環境所注入的政策實作與金鑰保管後端。