보안: 암호화, 암호화 정책 및 서명 표면
한눈에 보기
섹션 제목: “한눈에 보기”Core 보안 모듈은 AES-256 문서 암호화를 적용하고, 모든 알고리즘 선택을 암호화 정책 계약으로 게이트하며, 배포 환경이 키 관리 서비스를 연결할 때 사용하는 통합 지점을 노출합니다. 실질적인 문서 보호 수준은 키 처리, 비밀번호 강도, 문서를 읽는 리더, 배포 환경에 달려 있으며, 이 페이지에서는 각 경계를 명확하게 설명합니다.
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 구현을 문서화하지는 않습니다.
API 표면
섹션 제목: “API 표면”| 유형 | 종류 | 주요 멤버 | 안정성 | 도입 |
|---|---|---|---|---|
Document::setEncryption() | 메서드 (관심사 HasSecurity) | userPassword, ownerPassword, permissions | 안정 | 1.0.0 |
Document::useAesGcm() | 메서드 (관심사 HasSecurity) | ?bool $enabled — 선택적 ISO/TS 32003 V=6/R=7 | 안정 | 2.18.0 |
Aes256Encryptor | class | encrypt(), decrypt(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms() | 안정 | 1.0.0 |
Aes256GcmEncryptor | class | encrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount() | 안정 | 2.18.0 |
KeyMaterial | final readonly class | generate(), exposeKey(), fingerprint() | 안정 | 2.18.0 |
CryptoPolicyInterface | interface | isHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName() | 안정 | 1.9.0 |
Config::withCryptoPolicy() | 메서드 | CryptoPolicyInterface $policy | 안정 | 1.9.0 |
CryptoCapabilities | final class | hasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile() | 안정 | 2.0.0 |
코드 샘플 — 빠른 시작
섹션 제목: “코드 샘플 — 빠른 시작”<?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');사용자 비밀번호는 문서를 엽니다. 소유자 비밀번호는 전체 액세스를 부여합니다. 권한 플래그는 준수하는 리더에만 제약으로 작동합니다.
코드 샘플 — 프로덕션
섹션 제목: “코드 샘플 — 프로덕션”<?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트레일러 키를 금지하므로, PDF/A 관리자가 활성 상태일 때setEncryption()과useAesGcm()은 예외를 발생시킵니다. - 빈 소유자 비밀번호는
setEncryption()내부에서 사용자 비밀번호로 대체됩니다. 단일 공유 비밀번호를 사용하는 문서는 사용자 비밀번호 보유자에게 소유자 수준의 액세스를 부여합니다. CryptoPolicyInterface는 정책이 주입되지 않으면 모든 알고리즘을 허용합니다. 열린 기본값을 개발 편의로 취급하고, 규제 대상 배포 환경에서는 명시적 정책을 설정하십시오.- 권한 플래그는 리더에 대한 권고 성격입니다. 이를 악의적인 프로세서가 우회할 수 없는 액세스 제어로 기술하지 마십시오.
setEncryption()은 문서 빌드 시점에 반복적 키 파생 루틴(Algorithm 2.B, revision 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는 제어 수단을 노출하지만 순환 정책은 배포 환경이 설정합니다.
데이터 레지던시 및 PII 완화
섹션 제목: “데이터 레지던시 및 PII 완화”암호화 표면은 문서 바이트를 호스트 외부로 전송하지 않습니다. 키 파생, 암호화, 복호화는 프로세스 내에서 실행됩니다. 선택적 GCM 경로는 메모리 내 IV 충돌 집합을 키 바이트가 아니라 비가역적 키 지문으로 식별합니다. 보안 모듈은 어떤 비밀번호나 키 값도 디스크에 기록하지 않습니다. 외부 키 관리 서비스를 통해 키를 라우팅하는 배포 환경은 해당 서비스의 레지던시에 대한 책임을 집니다.
안전한 텔레메트리 및 로그 스크러빙
섹션 제목: “안전한 텔레메트리 및 로그 스크러빙”KeyMaterial::__toString()과 __debugInfo()는 가려진 자리표시자를 반환하므로, 키 객체가 실수로 로깅되어도 키 바이트가 아니라 지문이 출력됩니다. setEncryption()에 전달된 비밀번호는 #[\SensitiveParameter] 어트리뷰트를 지니며, 이는 스택 트레이스에서 비밀번호를 가립니다. 암호화 연산에 대한 감사 친화적 식별자는 CryptoPolicyInterface::getName()의 정책 이름과 8자리 키 지문입니다. 키나 비밀번호 대신 이러한 식별자를 로깅하십시오.
위협 모델
섹션 제목: “위협 모델”| 위협 | Core 의 완화책 | 잔여 경계 |
|---|---|---|
| 알고리즘 다운그레이드 / 약한 암호 대체 | 암호화 정책 게이트. 조용한 저하 없음(UnsupportedAlgorithmException 발생) | 정책이 주입된 경우에만 효과가 있음 |
| 로그를 통한 키 노출 | KeyMaterial 가림. 비밀번호에 #[\SensitiveParameter] 적용 | 호출자가 exposeKey()를 로거에 전달하면 이를 무력화함 |
| 암호문 변조 | 선택적 경로의 GCM 태그 검증 | 기본 CBC 경로는 기밀성 전용임 |
| IV 재사용(GCM) | 단조 증가 카운터와 충돌 집합. 롤오버 시 거부 | — |
| 권한 플래그 우회 | 없음 — 플래그는 권고적임 | 준수하지 않는 리더는 플래그를 무시함 |
| 약한 비밀번호에 대한 무차별 대입 | SASLprep와 반복적 키 파생이 비용을 높임 | 약한 비밀번호는 여전히 주된 위험으로 남음 |
FIPS 모드 동작
섹션 제목: “FIPS 모드 동작”Core는 FIPS 검증 암호화 모듈이 아니며 FIPS 인증을 받지 않았습니다. CryptoCapabilities::detectFipsMode()는 최선 노력 런타임 프로브입니다. 운영자 재정의를 확인한 다음 OpenSSL 제공자 목록과 레거시 FIPS 모드 호출을 차례로 확인하고, active, absent, 또는 indeterminate를 보고합니다. assertFipsAvailableForProfile()는 FIPS 제공자를 증명하지 못하는 호스트에서 FIPS 프로필이 선택되면 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 모드 암호화 정책 프로필을 제공합니다. 계약 표면은 에디션 전반에 걸쳐 동일하며, 차이는 정책 구현과 배포 환경이 주입하는 키 보관 백엔드입니다.
관련 항목
섹션 제목: “관련 항목”- 보안 / 암호화 — AES-256 및 AES-256-GCM 심화 참조.
- 계약 / 보안 정책 — 암호화 정책 및 리소스 정책 계약.
- 보안 / 서명 — PAdES 서명, CMS, 그리고 타임스탬프.
- 감사 — 정책 이름 및 연산 감사 로깅.
- 준수 — 암호화와 PDF/A의 상호작용.