跳轉到

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 SDK(Pro 不自動引入,避免版本衝突)
composer require aws/aws-sdk-php ^3.300

AWS KMS 金鑰必須為非對稱金鑰,用途設為 SIGN_VERIFY,金鑰規格建議 RSA_4096ECC_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 整合

composer require microsoft/microsoft-graph ^2.0
# 或使用 Azure SDK for PHP(預覽版)
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 金鑰不符 確認憑證與金鑰對齊

安全最佳實踐

  1. 最小權限原則:IAM Role 只需要 kms:Signkms:GetPublicKey,不授予 kms:Decryptkms:GenerateDataKey
  2. 審計日誌:啟用 AWS CloudTrail 或 Azure Monitor 記錄所有 KMS 簽章操作
  3. 輪換政策:建議每 2 年輪換非對稱金鑰,輪換前確保舊憑證涵蓋在 B-LT 驗證資料中
  4. 環境隔離:生產、暫存、開發使用各自獨立的 KMS 金鑰
  5. SoftHSM2 僅用於測試:不得在生產環境使用軟體 HSM

相關資源