HSM 硬體安全模組整合¶
硬體安全模組(HSM,Hardware Security Module)確保簽章私鑰永遠儲存在安全邊界內,任何應用程式程式碼都無法直接存取私鑰材料。NextPDF Pro 支援 AWS KMS、Azure Key Vault 以及任何符合 PKCS#11 v3.0 規格的硬體 HSM。
支援的 HSM 後端¶
| 後端 | 驅動類別 | 金鑰演算法 | 備注 |
|---|---|---|---|
| AWS KMS | AwsKmsSigningDriver | RSA-2048/4096、ECDSA P-256/P-384 | 支援 KMS 非對稱金鑰 |
| Azure Key Vault | AzureKeyVaultSigningDriver | RSA-2048/4096、ECDSA P-256/P-384/P-521 | Managed HSM 與 Premium 方案 |
| PKCS#11 通用 | Pkcs11SigningDriver | 依 HSM 型號而定 | Thales、Entrust、SafeNet 等 |
| SoftHSM2(測試用) | Pkcs11SigningDriver | RSA、ECDSA | 僅限開發/測試環境 |
AWS KMS 整合¶
前置條件¶
AWS KMS 金鑰必須為非對稱金鑰,用途設為 SIGN_VERIFY,金鑰規格建議 RSA_4096 或 ECC_NIST_P384。
設定 AWS KMS 簽章驅動¶
use NextPDF\Pro\Signatures\Hsm\Driver\AwsKmsSigningDriver;
use NextPDF\Pro\Signatures\Hsm\HsmSigningContext;
use NextPDF\Pro\Signatures\PAdES\PadesSignatureAppender;
use NextPDF\Pro\Signatures\PAdES\PadesSignatureLevel;
use NextPDF\Pro\Signatures\PAdES\PadesSignatureOptions;
use NextPDF\Pro\Signatures\Timestamp\TimestampAuthorityClient;
use Aws\Kms\KmsClient;
// 建立 AWS KMS 客戶端
$kmsClient = new KmsClient([
'region' => (string) getenv('AWS_REGION'),
'version' => 'latest',
// 生產環境:使用 IAM Role,不要硬編碼憑證
// 開發環境:credentials 可指向 ~/.aws/credentials
]);
// 建立 HSM 簽章驅動
$driver = new AwsKmsSigningDriver(
kmsClient: $kmsClient,
keyId: (string) getenv('AWS_KMS_KEY_ID'), // ARN 或別名
signingAlgorithm: 'RSASSA_PKCS1_V1_5_SHA_256',
);
// 建立簽章上下文(含公開憑證,私鑰留在 KMS)
$context = HsmSigningContext::fromDriver(
driver: $driver,
publicCertificatePem: file_get_contents('/certs/kms-public.pem'),
);
使用 KMS 執行 PAdES B-LTA 簽章¶
use NextPDF\Pro\Signatures\PAdES\PadesSignatureAppender;
use NextPDF\Pro\Signatures\PAdES\PadesSignatureLevel;
use NextPDF\Pro\Signatures\PAdES\PadesSignatureOptions;
use NextPDF\Pro\Signatures\Timestamp\TimestampAuthorityClient;
$tsa = new TimestampAuthorityClient(
url: 'https://tsa.example.com/timestamp',
username: (string) getenv('TSA_USERNAME'),
password: (string) getenv('TSA_PASSWORD'),
);
$options = PadesSignatureOptions::fromHsmContext(
hsmContext: $context,
level: PadesSignatureLevel::BLta,
timestampAuthority: $tsa,
reason: 'Board approval — AWS KMS signed',
location: 'AWS us-east-1',
);
$appender = new PadesSignatureAppender($options);
$signedPdf = $appender->sign($pdfBytes);
Azure Key Vault 整合¶
use NextPDF\Pro\Signatures\Hsm\Driver\AzureKeyVaultSigningDriver;
use NextPDF\Pro\Signatures\Hsm\HsmSigningContext;
$driver = new AzureKeyVaultSigningDriver(
vaultUrl: (string) getenv('AZURE_KEY_VAULT_URL'),
keyName: (string) getenv('AZURE_KEY_NAME'),
keyVersion: (string) getenv('AZURE_KEY_VERSION'), // 指定版本避免自動輪換干擾
tenantId: (string) getenv('AZURE_TENANT_ID'),
clientId: (string) getenv('AZURE_CLIENT_ID'),
clientSecret: (string) getenv('AZURE_CLIENT_SECRET'),
signingAlgorithm: 'RS256',
);
$context = HsmSigningContext::fromDriver(
driver: $driver,
publicCertificatePem: file_get_contents('/certs/azure-public.pem'),
);
PKCS#11 通用 HSM¶
適用於 Thales Luna、Entrust nShield、SafeNet ProtectServer 等物理或網路 HSM:
use NextPDF\Pro\Signatures\Hsm\Driver\Pkcs11SigningDriver;
use NextPDF\Pro\Signatures\Hsm\HsmSigningContext;
$driver = new Pkcs11SigningDriver(
libraryPath: '/usr/lib/softhsm/libsofthsm2.so', // HSM 廠商提供的 PKCS#11 library
tokenLabel: 'NextPDF-Production',
userPin: (string) getenv('HSM_USER_PIN'),
keyLabel: 'signing-key-2025',
mechanism: \NextPDF\Pro\Signatures\Hsm\Pkcs11Mechanism::RsaPkcs1Sha256,
);
$context = HsmSigningContext::fromDriver(
driver: $driver,
publicCertificatePem: file_get_contents('/certs/hsm-public.pem'),
);
XAdES 簽章支援¶
除 PAdES 外,Pro 亦支援 XAdES(XML Advanced Electronic Signatures)。XAdES 適用於需要同時對 XML 資料與 PDF 進行簽章的場景,如電子發票系統:
use NextPDF\Pro\Signatures\XAdES\XadesSignatureBuilder;
use NextPDF\Pro\Signatures\XAdES\XadesSignatureLevel;
use NextPDF\Pro\Signatures\XAdES\XadesSignatureOptions;
// XAdES-B-LT:含長期驗證資料的 XML 簽章
$xadesOptions = XadesSignatureOptions::create(
level: XadesSignatureLevel::BLt,
hsmContext: $context, // 同一個 HsmSigningContext 可跨格式使用
timestampAuthority: $tsa,
signaturePolicy: 'http://uri.etsi.org/19182/SignaturePolicy/v1',
signerRole: 'CFO',
);
$builder = new XadesSignatureBuilder($xadesOptions);
// 對 PDF 位元組產生 XAdES 信封式簽章
$xadesXml = $builder->enveloping($pdfBytes);
// 或對 XML 文件產生內嵌式簽章
$signedXml = $builder->enveloped($xmlDocument);
XAdES 等級對照¶
| XAdES 等級 | 對應 PAdES 等級 | 說明 |
|---|---|---|
| B-B | B-B | 基礎簽章 |
| B-T | B-T | 含時間戳記 |
| B-LT | B-LT | 含撤銷資料 |
| B-LTA | B-LTA | 追加封存時間戳記 |
金鑰輪換策略¶
生產環境下,簽章金鑰應定期輪換。NextPDF Pro 提供金鑰版本管理支援:
use NextPDF\Pro\Signatures\Hsm\KeyVersionRegistry;
$registry = new KeyVersionRegistry(
activeKeyId: (string) getenv('AWS_KMS_KEY_ID_V3'),
legacyKeyIds: [
getenv('AWS_KMS_KEY_ID_V2'),
getenv('AWS_KMS_KEY_ID_V1'),
],
);
// 新簽章使用最新金鑰
$driver = new AwsKmsSigningDriver($kmsClient, $registry->getActiveKeyId(), 'RSASSA_PKCS1_V1_5_SHA_256');
// 驗證時能識別舊金鑰簽署的文件
$validator = new PadesSignatureValidator(keyVersionRegistry: $registry);
錯誤處理¶
| 例外類別 | 觸發條件 | 建議處理 |
|---|---|---|
HsmConnectionException | 無法連線至 HSM / KMS 端點 | 重試 + 電路斷路器 |
HsmAuthenticationException | IAM 權限不足或 PIN 錯誤 | 立即告警,不重試 |
HsmKeyNotFoundException | 金鑰 ID 不存在或已停用 | 驗證環境變數設定 |
SigningAlgorithmMismatchException | 憑證演算法與 HSM 金鑰不符 | 確認憑證與金鑰對齊 |
安全最佳實踐¶
- 最小權限原則:IAM Role 只需要
kms:Sign和kms:GetPublicKey,不授予kms:Decrypt或kms:GenerateDataKey - 審計日誌:啟用 AWS CloudTrail 或 Azure Monitor 記錄所有 KMS 簽章操作
- 輪換政策:建議每 2 年輪換非對稱金鑰,輪換前確保舊憑證涵蓋在 B-LT 驗證資料中
- 環境隔離:生產、暫存、開發使用各自獨立的 KMS 金鑰
- SoftHSM2 僅用於測試:不得在生產環境使用軟體 HSM