跳轉到

SEC Rule 17a-4 WORM 合規

SEC Rule 17a-4(f) 要求受監管的金融機構(券商、投資顧問、交易所)以不可改寫、不可刪除(WORM)的方式保留電子通訊記錄與業務文件,保存期限依文件類型從 2 年至 6 年不等。


法規要求對應

Rule 17a-4(f) 要求 技術含義 NextPDF Enterprise 實現
不可改寫(Non-rewriteable) 寫入後無法修改任何位元 WORM 封存鎖定,SHA-512 完整性封印
不可刪除(Non-erasable) 保留期內無法刪除 保留期政策強制執行,刪除請求拒絕並記錄
序列化存取控制 防止未授權存取 mTLS + 租戶隔離存取控制
即時索引(Real-time index) 支援 SEC 審查人員快速存取 結構化索引、全文檢索 API
指定第三方下載能力 SEC 可直接提取記錄 SecAuditorAccessGrant API
書面說明(Written undertaking) 機構需提交合規聲明 合規報告產生器

核心 API

WormArchive

use NextPDF\Enterprise\Compliance\Sec\WormArchive;
use NextPDF\Enterprise\Compliance\Sec\RetentionPolicy;
use NextPDF\Enterprise\Compliance\Sec\ArchiveRecord;

$retentionPolicy = RetentionPolicy::create(
    documentType: 'broker-dealer-communication',
    retentionYears: 3,
    retentionMonths: 0,
    allowEarlyDeletion: false,
    legalHoldCapable: true,
);

$archive = new WormArchive(
    storageAdapter: $s3WormAdapter, // S3 Object Lock 或同等 WORM 儲存
    retentionPolicy: $retentionPolicy,
    integrityAlgorithm: 'SHA-512',
);

$record = $archive->store(
    document: $pdfBytes,
    metadata: ArchiveRecord::create(
        documentId: $docId,
        documentType: 'trade-confirmation',
        entityId: 'BD-12345',
        createdAt: new DateTimeImmutable(),
        retentionUntil: new DateTimeImmutable('+3 years'),
    )
);

// $record->archiveId() — 不可變封存 ID
// $record->integrityHash() — SHA-512 完整性雜湊
// $record->retentionExpiry() — 保留到期日

PHP Compatibility

This example uses PHP 8.5 syntax. If your environment runs PHP 8.1 or 7.4, use NextPDF Backport for a backward-compatible build.

RetentionPolicy

use NextPDF\Enterprise\Compliance\Sec\RetentionPolicy;
use NextPDF\Enterprise\Compliance\Sec\DocumentType;

// 預設保留期(依 Rule 17a-4 規定)
$policy = RetentionPolicy::forDocumentType(DocumentType::TradeConfirmation);        // 3 年
$policy = RetentionPolicy::forDocumentType(DocumentType::CustomerComplaint);        // 4 年
$policy = RetentionPolicy::forDocumentType(DocumentType::FinancialStatement);       // 6 年
$policy = RetentionPolicy::forDocumentType(DocumentType::BrokerDealerAgreement);    // 6 年
$policy = RetentionPolicy::forDocumentType(DocumentType::ElectronicCommunication);  // 3 年(2022 修正)

SecIndexBuilder

Rule 17a-4(f)(3)(iii) 要求維護可供 SEC 審查的索引:

use NextPDF\Enterprise\Compliance\Sec\SecIndexBuilder;
use NextPDF\Enterprise\Compliance\Sec\IndexQuery;

$indexBuilder = new SecIndexBuilder($archive);

// 產生符合 SEC 要求的索引報告
$index = $indexBuilder->buildIndex(
    dateRange: new DateRange(
        from: new DateTimeImmutable('2024-01-01'),
        to: new DateTimeImmutable('2024-12-31'),
    ),
    documentTypes: [DocumentType::TradeConfirmation, DocumentType::CustomerComplaint],
    format: IndexFormat::Csv,  // SEC 偏好 CSV 格式
);

// 授予 SEC 審查人員存取
$accessGrant = $indexBuilder->grantAuditorAccess(
    auditorId: 'SEC-EXAM-2025-001',
    expiresAt: new DateTimeImmutable('+30 days'),
    scope: AccessScope::ReadOnly,
);

完整性驗證

WORM 封存後,任何時刻均可驗證文件未被竄改:

use NextPDF\Enterprise\Compliance\Sec\IntegrityVerifier;

$verifier = new IntegrityVerifier($archive);

$result = $verifier->verify(archiveId: $record->archiveId());

if (!$result->isIntact()) {
    // 觸發 SEC 強制要求的事件通報程序
    $incidentReporter->reportIntegrityBreach(
        archiveId: $record->archiveId(),
        detectedAt: new DateTimeImmutable(),
        expectedHash: $result->expectedHash(),
        actualHash: $result->actualHash(),
    );
}

封存文件生命週期

flowchart LR
    A[文件建立] --> B[WORM 封存]
    B --> C{法律留存?}
    C -->|是| D[延長保留]
    D --> E{留存解除?}
    E -->|是| C
    E -->|否| F[繼續保留]
    C -->|否| G{保留期到期?}
    G -->|否| H[定期完整性驗證]
    H --> G
    G -->|是| I[SEC 通知確認]
    I --> J[安全銷毀]
    J --> K[銷毀稽核記錄]

案例:交易確認書封存

use NextPDF\Enterprise\Compliance\Sec\SecComplianceBundle;

$bundle = SecComplianceBundle::create(
    storageAdapter: $s3WormAdapter,
    indexAdapter: $elasticsearchAdapter,
);

// 批次封存每日交易確認書
foreach ($dailyConfirmations as $confirmation) {
    $pdf = $pdfFactory->createTradeConfirmation($confirmation);

    $bundle->archiveAndIndex(
        document: $pdf,
        type: DocumentType::TradeConfirmation,
        entityId: $confirmation->brokerId(),
        referenceId: $confirmation->tradeId(),
    );
}

// 產生月度合規報告
$report = $bundle->generateComplianceReport(
    period: ReportingPeriod::lastMonth(),
    includeIntegrityAudit: true,
);

延伸閱讀