Skip to content

安全最佳實踐

本指南提供在正式環境中部署 TCPDF-Next 的可行安全建議。遵循這些實踐可確保您的數位簽章、加密與文件產生符合企業級安全標準。

憑證管理

取得憑證

在正式環境中使用數位簽章時,請使用受信任憑證授權機構(CA)所核發的憑證:

憑證類型使用情境典型有效期費用
文件簽署(個人)個人簽章1-3 年$50-200/年
文件簽署(組織)企業全域簽章1-3 年$200-500/年
合格憑證(eIDAS)歐盟法律效力1-3 年$100-400/年
Adobe AATL 憑證在 Adobe Acrobat 中預設信任1-3 年$300-1000/年

TIP

若您的簽章需要在 Adobe Acrobat 中無需手動設定信任即可被認可,請使用 Adobe 核准信任清單(AATL) 上的 CA 所核發的憑證。

憑證輪替

php
use YeeeFang\TcpdfNext\Certificate\CertificateStore;

$store = new CertificateStore();

// 從安全目錄載入憑證
$store->loadFromDirectory('/etc/tcpdf-next/certs/', '*.pem');

// 自動選取有效且未過期的憑證
$activeCert = $store->getActiveCertificate('document-signing');

if ($activeCert->getExpirationDate() < new \DateTimeImmutable('+30 days')) {
    // 觸發憑證續期警報
    $logger->warning('簽署憑證將在 30 天內到期', [
        'subject' => $activeCert->getSubject(),
        'expires' => $activeCert->getExpirationDate()->format('Y-m-d'),
    ]);
}

建議事項:

  • 至少在到期前 30 天進行憑證續期
  • 透過自動化警報監控憑證到期時間
  • 立即撤銷已遭洩漏的憑證
  • 維護所有憑證操作的記錄

私鑰儲存

儲存方式階層(從最安全到最不安全)

方式安全等級使用情境
硬體安全模組(HSM)最高企業級、受監管產業
雲端 KMS(AWS KMS、Azure Key Vault、GCP KMS)雲端原生部署
具強密碼短語的 PKCS#12 檔案小型部署
PEM 檔案(加密)中低開發、測試
PEM 檔案(未加密)最低正式環境中絕不使用

使用 HSM(建議方式)

php
use YeeeFang\TcpdfNext\Signature\Pkcs11Signer;

// 透過 PKCS#11 使用硬體安全模組
$signer = new Pkcs11Signer(
    modulePath: '/usr/lib/softhsm/libsofthsm2.so',
    slotId: 0,
    pin: getenv('HSM_PIN'), // PIN 碼從環境變數取得
    keyLabel: 'signing-key-2026'
);

$pdfSigner = new PdfSigner($pdf);
$pdfSigner->setExternalSigner($signer)
    ->setLevel(SignatureLevel::PAdES_B_LTA)
    ->sign();

使用雲端 KMS

php
use YeeeFang\TcpdfNext\Signature\CloudKmsSigner;

// AWS KMS 範例
$signer = CloudKmsSigner::awsKms(
    keyId: 'arn:aws:kms:eu-west-1:123456789:key/abcd-1234',
    region: 'eu-west-1',
    algorithm: 'RSASSA_PSS_SHA_256'
);

// Azure Key Vault 範例
$signer = CloudKmsSigner::azureKeyVault(
    vaultUrl: 'https://my-vault.vault.azure.net',
    keyName: 'signing-key',
    keyVersion: 'abc123',
    algorithm: 'RS256'
);

// Google Cloud KMS 範例
$signer = CloudKmsSigner::gcpKms(
    keyName: 'projects/my-project/locations/europe-west1/keyRings/signing/cryptoKeys/doc-signing/cryptoKeyVersions/1',
    algorithm: 'RSA_SIGN_PSS_2048_SHA256'
);

PKCS#12 檔案搭配密碼短語

php
// 從檔案載入 PKCS#12,密碼短語從環境變數取得
$p12Content = file_get_contents('/etc/tcpdf-next/keys/signing.p12');
$passphrase = getenv('SIGNING_KEY_PASSPHRASE');

$certs = [];
openssl_pkcs12_read($p12Content, $certs, $passphrase);

$signer = new PdfSigner($pdf);
$signer->setCertificate($certs['cert'], $certs['pkey'])
    ->setLevel(SignatureLevel::PAdES_B_LTA)
    ->sign();

// 從記憶體清除機敏資料
sodium_memzero($passphrase);
sodium_memzero($certs['pkey']);

DANGER

切勿將私鑰儲存於:

  • 原始碼儲存庫中
  • 在程序清單中可見的環境變數
  • 共享檔案系統上的未加密檔案
  • 未加密的資料庫欄位
  • 日誌檔案或錯誤訊息中

時間戳記伺服器選擇

選擇 TSA 的標準

標準需求
RFC 3161 合規必要
TLS(HTTPS)必要
回應時間< 2 秒
可用性99.9%+ SLA
雜湊演算法SHA-256、SHA-384、SHA-512
憑證有效期10 年以上
稽核軌跡提供
地理位置考量資料駐留要求

建議的 TSA 供應商

供應商網址備註
DigiCerthttps://timestamp.digicert.com廣受信任,AATL 成員
Sectigohttps://timestamp.sectigo.com全球可用性佳
GlobalSignhttps://timestamp.globalsign.com歐洲供應商
FreeTSAhttps://freetsa.org/tsr免費,適合測試用途

WARNING

免費 TSA 服務可能無法提供正式環境所需的可靠性、SLA 或稽核軌跡。對於具法律效力的簽章,請使用商用 TSA 供應商。

TSA 容錯備援

設定多個 TSA 伺服器以實現高可用性:

php
use YeeeFang\TcpdfNext\Timestamp\TsaPool;

$tsaPool = TsaPool::create()
    ->addServer('https://timestamp.digicert.com', priority: 1)
    ->addServer('https://timestamp.sectigo.com', priority: 2)
    ->addServer('https://timestamp.globalsign.com', priority: 3)
    ->setFailoverStrategy('priority'); // 或 'round-robin'

$signer->setTimestampClient($tsaPool);

簽章驗證

驗證外部來源的 PDF

接受來自外部的已簽署 PDF 時,務必驗證簽章:

php
use YeeeFang\TcpdfNext\Signature\SignatureValidator;
use YeeeFang\TcpdfNext\Certificate\CertificateStore;

$trustStore = new CertificateStore();
$trustStore->loadFromDirectory('/etc/tcpdf-next/trusted-roots/');

$validator = new SignatureValidator($trustStore);
$result = $validator->validate('/path/to/received.pdf');

if (!$result->isValid()) {
    foreach ($result->getErrors() as $error) {
        $logger->error('簽章驗證失敗', [
            'error' => $error->getMessage(),
            'code' => $error->getCode(),
        ]);
    }
    throw new \RuntimeException('無效的簽章');
}

驗證檢查清單

確保您的驗證流程檢查以下項目:

  • [ ] 簽章完整性(CMS 簽章驗證通過)
  • [ ] 憑證鏈(簽署者到受信任根憑證)
  • [ ] 憑證有效性(未過期、未撤銷)
  • [ ] 金鑰用途(已設定 digitalSignature 位元)
  • [ ] 位元範圍覆蓋(整份文件已簽署)
  • [ ] 無未經授權的簽署後修改
  • [ ] 時間戳記有效性(如有)
  • [ ] 演算法合規性(無 SHA-1、無弱金鑰)

安全部署

環境設定

bash
# .env(Laravel 範例)

# 簽署憑證(PKCS#12)
TCPDF_SIGNING_CERT_PATH=/etc/tcpdf-next/certs/signing.p12
TCPDF_SIGNING_CERT_PASSPHRASE=  # 透過秘密管理器設定,勿寫在 .env

# 時間戳記伺服器
TCPDF_TSA_URL=https://timestamp.digicert.com
TCPDF_TSA_HASH_ALGORITHM=SHA-256

# 安全政策
TCPDF_MIN_RSA_KEY_SIZE=2048
TCPDF_REJECT_SHA1=true
TCPDF_STRICT_PARSING=true

# 資源限制
TCPDF_MAX_MEMORY=256M
TCPDF_MAX_EXECUTION_TIME=120
TCPDF_MAX_PDF_SIZE=104857600

檔案系統權限

bash
# 憑證目錄:僅允許 Web 伺服器使用者讀取
chown -R www-data:www-data /etc/tcpdf-next/certs/
chmod 700 /etc/tcpdf-next/certs/
chmod 600 /etc/tcpdf-next/certs/*.p12
chmod 600 /etc/tcpdf-next/certs/*.pem

# 輸出目錄:僅允許 Web 伺服器使用者寫入
chown -R www-data:www-data /var/lib/tcpdf-next/output/
chmod 700 /var/lib/tcpdf-next/output/

# 暫存目錄:可寫入,非全域可讀
chown -R www-data:www-data /tmp/tcpdf-next/
chmod 700 /tmp/tcpdf-next/

內容安全

從使用者提供的內容(HTML、圖片)產生 PDF 時:

php
use YeeeFang\TcpdfNext\Security\ResourcePolicy;
use YeeeFang\TcpdfNext\Security\NetworkPolicy;

// 嚴格限制資源載入
$resourcePolicy = ResourcePolicy::strict()
    ->allowLocalDirectory('/app/public/assets/')
    ->denyAllRemote(); // 禁止所有外部資源擷取

// 若確實需要遠端資源
$networkPolicy = NetworkPolicy::create()
    ->denyPrivateNetworks()
    ->denyLoopback()
    ->denyLinkLocal()
    ->allowDomain('cdn.yourcompany.com')
    ->setMaxRedirects(3)
    ->setRequestTimeout(10);

$pdf = PdfDocument::create()
    ->setResourcePolicy($resourcePolicy)
    ->setNetworkPolicy($networkPolicy)
    ->build();

速率限制

對於公開的 PDF 產生 API,實施速率限制:

php
// Laravel 中介軟體範例
Route::post('/api/generate-pdf', [PdfController::class, 'generate'])
    ->middleware('throttle:pdf-generation');

// 在 RouteServiceProvider 中
RateLimiter::for('pdf-generation', function (Request $request) {
    return Limit::perMinute(10)->by($request->user()->id);
});

合規檢查清單

財務文件

  • [ ] 使用 PAdES B-LTA 簽章確保長期有效性
  • [ ] 使用 AATL 清單上的憑證取得 Adobe 信任
  • [ ] 使用具 SLA 的商用 TSA
  • [ ] 嵌入所有驗證資料(OCSP + CRL)
  • [ ] 保留簽署稽核日誌直至監管要求期限
  • [ ] 使用 PDF/A-4 滿足歸檔需求

醫療保健(HIPAA)

  • [ ] 以 AES-256 加密含 PHI 的 PDF
  • [ ] 使用憑證式(公鑰)加密實現多收件者存取
  • [ ] 記錄所有簽署金鑰的存取行為
  • [ ] 將簽署金鑰儲存於 HSM 或雲端 KMS
  • [ ] 為所有已簽署文件實施稽核軌跡

歐盟 eIDAS 合規

  • [ ] 使用 eIDAS 合格 TSP 核發的合格憑證
  • [ ] 使用 eIDAS 合格 TSA 的合格時間戳記
  • [ ] 實作 PAdES B-LTA 以取得合格電子簽章
  • [ ] 確保 PDF/A-4 合規以維持長期有效性

延伸閱讀

以 LGPL-3.0-or-later 授權釋出。