콘텐츠로 이동
getnextpdf.com

Enterprise 에디션

콘텐츠 무장 해제 및 재구성 (CDR)

NextPDF Enterprise는 콘텐츠 무장 해제 및 재구성(CDR)을 통해 신뢰할 수 없는 PDF를 무력화합니다. 파일을 파싱하고, 수용 한도와 대조하여 검사하고, 위험한 기능을 탐지하고, 이를 제거한 뒤, 남은 객체로부터 새 파일을 재구성합니다. 위험한 기능은 활성 콘텐츠 — 임베드된 스크립트, 실행 액션, 임베드된 파일, 리치 미디어 등 —로, 뷰어가 실행하거나 작동시킬 수 있는 것들입니다. 이 페이지는 동작 수준입니다. 엔진이 무엇을 받아들이고, 무엇을 제거하고, 무엇을 재구성하며, 출력이 증거용 사본이 아닌 이유를 명시합니다.

CDR은 파괴적이고 단방향인 변환입니다. 재구성된 출력은 입력의 보안 투영이며, 보존되거나 해시가 동등한 사본이 아닙니다. 그 경계는 보안 및 규정 준수에서 명시됩니다.

사전 요구 사항은 프런트 매터에 명시되어 있으며 사전 요구 사항에서 반복됩니다.

이 기능은 NextPDF Enterprise(nextpdf/enterprise)로 제공되며 Enterprise 등급 라이선스 엔벨로프로 활성화됩니다. 해당 사용권이 없는 배포는 이 기능의 클래스를 로드하지 않습니다. NextPDF Core와 NextPDF Pro는 CDR을 제공하지 않습니다. 엔진은 인프로세스로 실행됩니다. 신뢰할 수 없는 문서는 귀하의 호스트에서 파싱되고 재구성됩니다. 에디션 비교 및 라이선스 받기.

PDF는 뷰어가 실행하거나 작동시킬 수 있는 활성 콘텐츠를 지원합니다. ECMAScript 액션은 PDF 프로세서가 필드 값과 외관을 변경할 수 있는 스크립트를 실행하게 합니다(ISO 32000-2 §12.6.4). 실행 액션은 애플리케이션을 실행하거나 문서를 열거나 인쇄합니다(ISO 32000-2 §12.6.4). 네임 딕셔너리의 문서 수준 스크립트는 문서가 열릴 때 자동으로 실행됩니다(ISO 32000-2 §7.7.4). CDR은 이러한 표면을 제거합니다.

엔진은 순서가 있는 파이프라인을 실행합니다.

  1. 입력 PDF를 파싱합니다.
  2. 수용 제어 — 문서가 수용 경계(객체 수, 페이지 수, 디코딩된 스트림 크기, 그리고 압축 해제 폭탄(decompression-bomb) 입력을 방어하는 스트림 팽창 비율) 안에 있는지 검증합니다. 한도를 벗어난 문서는 정화되는 것이 아니라 거부됩니다. 거부는 정화 결과와 구별되게 보고되므로 귀하의 오류 처리가 둘을 구분할 수 있습니다.
  3. 위협 탐지 — 구성된 위협 유형을 스캔합니다.
  4. 필터링 — 객체를 안전 집합과 제거 집합으로 분할합니다.
  5. 참조 스크럽 — 제거로 인해 매달린(dangling) 포인터를 정리합니다.
  6. 재구성 — 안전한 객체를 새 PDF로 직렬화합니다.

탐지 가능한 위협 유형에는 임베드된 스크립트(및 잘못된 구조 안의 스크립트를 잡아내는 공격적 스크립트 제거), 추가 액션(additional-actions) 및 열기 액션(open-action) 트리거, 실행 액션, 원격 이동(remote go-to) 액션, 폼 제출 및 데이터 가져오기 액션, 임베드된 파일, 리치 미디어 및 3차원 콘텐츠, 문서 수준 스크립트 네임 트리, 외부 URI(Uniform Resource Identifier) 액션, XML Forms Architecture 데이터, 대화형 폼 필드, 기본값이 아닌 선택적 콘텐츠 레이어, 그리고 디지털 서명 객체(바이트 범위가 더 이상 일치하지 않으므로 재구성이 필연적으로 무효화함)가 포함됩니다. 파싱할 수 없는 객체는 그 자체가 잠재적 우회로 취급되어 제거됩니다.

세 가지 정책이 기본값을 설정합니다.

  • Standard — 엔진이 탐지 가능하고 구성된 활성 콘텐츠 위협 유형을 제거합니다. 증분 업데이트는 서명 섀도잉(signature-shadowing)을 방어하기 위해 항상 평탄화되며, 이 모드에서 그 평탄화는 구성할 수 없습니다.
  • Paranoid — 동일한 제거를 더 엄격한 리소스 한도와 함께 수행합니다.
  • Permissive — 신뢰할 수 있는 출처용입니다. 스크립트와 실행 액션을 제거하되 URI 액션은 보존하며, 증분 업데이트 평탄화를 구성 가능하게 만듭니다.

CDR은 위험한 키를 제자리에서 삭제하는 대신, 안전하다고 판단한 객체로부터 새 파일을 재구성합니다. 그 허용 목록(allow-list) 태세가 핵심 결정입니다. 탐지기가 인식하지 못한 객체 — 파싱할 수 없었던 객체를 포함 —는 출력으로 살아남지 못하므로, 알 수 없는 구조는 거부 목록(deny-list)의 틈으로 빠져나가는 대신 안전하게 실패(fail closed)합니다. 수용 제어가 먼저 실행되는 것도 같은 이유입니다. 한도를 초과하거나 파싱할 수 없는 입력은 부분적으로 재구성되는 일 없이 즉시 거부됩니다. 그 안전의 대가는 보존입니다. 재구성은 바이트 레이아웃을 바꾸고, 서명을 무효화하며, 위협 유형이 제거된 페이로드를 버립니다 — 이것이 출력이 증거용 사본이 결코 아니라 보안 투영인 이유입니다.

설계 배경: 신뢰할 수 없는 PDF 정화: 콘텐츠 무장 해제 및 재구성.

  1. NextPDF Core와 Enterprise 패키지를 설치하고, 활성 Enterprise 라이선스를 보유하십시오.
  2. 입력에 대한 수용 경계 — 최대 객체 수, 페이지 수, 디코딩된 스트림 크기, 팽창 비율 —을 정의하거나, 사전 설정 정책의 한도를 사용하십시오.
  3. 정책을 결정하십시오. 일반적인 신뢰할 수 없는 수신에는 standard, 가장 엄격한 태세에는 paranoid, 신뢰할 수 있는 출처에만 permissive입니다.

정책은 불변이며 다음을 담습니다.

  • 제거할 위협 유형 — 탐지기가 스캔하고 재구성기가 제거하는 집합.
  • URI 액션 처리 — 외부 URI 액션을 보존할지 여부.
  • 증분 업데이트 평탄화 — standard 및 paranoid에서는 항상 켜져 있음; permissive에서는 구성 가능.
  • 수용 한도 — 최대 객체 수, 페이지 수, 디코딩된 스트림 크기, 팽창 비율. 이것들은 정화 동작이 아니라 수용 경계입니다. 이를 초과하면 문서가 거부됩니다.
  1. 신뢰할 수 없는 PDF 바이트를 읽습니다.
  2. 정책(standard, paranoid, 또는 permissive)을 선택하거나 명시적 한도로 하나를 빌드합니다.
  3. 바이트와 정책으로 엔진의 정화 작업을 실행합니다.
  4. 결과를 검사합니다. 수용되지 않음으로 보고되면 거부 사유를 표시하고, 그렇지 않으면 재구성된 바이트와 제거된 위협 목록을 사용합니다.
  5. 재구성된 출력을 정화된 투영으로 취급하고, 결코 입력의 증거용 또는 아카이브용 사본으로 취급하지 마십시오.
examples/enterprise/cdr-sanitize-guarded.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Enterprise\Security\Cdr\CdrEngine;
use NextPDF\Enterprise\Security\Cdr\CdrPolicy;
use NextPDF\Enterprise\Security\Cdr\CdrResult;
use Psr\Log\LoggerInterface;
final readonly class UntrustedPdfIntake
{
public function __construct(
private CdrEngine $engine,
private LoggerInterface $logger,
) {}
/**
* Sanitize an untrusted PDF and distinguish rejection from a clean rebuild.
*
* An over-limit document is rejected by admission control, not sanitized;
* the caller surfaces the rejection reason instead of trusting an empty
* output. The rebuilt bytes are a security projection, never an
* evidentiary copy of the input.
*
* @param string $pdfBytes The untrusted PDF bytes.
*
* @return CdrResult The sanitization result, including admission status.
*/
public function sanitize(string $pdfBytes): CdrResult
{
$result = $this->engine->sanitize($pdfBytes, CdrPolicy::standard());
if (! $result->admitted) {
$this->logger->warning('PDF rejected by CDR admission control', [
'reason' => $result->rejectionReason,
]);
return $result;
}
$this->logger->info('PDF sanitized', [
'removedThreats' => \count($result->removedThreats),
'originalSize' => $result->originalSize,
'sanitizedSize' => $result->sanitizedSize,
]);
return $result;
}
}
  1. 알려진 활성 콘텐츠 표면(예: 문서 수준 스크립트)을 담은 샘플을 실행하고, 그것이 제거된 위협 목록에 나타나며 재구성된 출력에는 없는지 확인하십시오.
  2. 한도를 초과하는 문서를 실행하고, 결과가 거부 사유와 함께 수용되지 않음으로 보고되며 재구성된 바이트가 비어 있는지 확인하십시오.
  3. 디지털 서명된 입력이 재구성 시 서명 객체가 제거되는지 확인하십시오 — 재구성은 바이트 범위가 변경되므로 원본 서명을 무효화하며, 따라서 오래된 서명 객체는 설계상 제거됩니다.
  4. 재구성된 출력을 뷰어에서 열고 열 때 어떤 스크립트도 실행되지 않는지 확인하십시오.
  • 증거용이 아닙니다. 재구성된 출력은 파괴적이고 비가역적인 투영입니다. 법적 증거 보존, 원본과의 해시 비교, 또는 아카이브용 사본으로 사용하지 마십시오. 증거용 사본이 필요하면 원본을 별도의 보관 하에 유지하십시오.
  • 정화 이전의 수용. 리소스 한도는 수용 경계입니다. 한도를 초과하는 문서는 정화되는 것이 아니라 거부됩니다. 한도를 초과하는 입력이 결코 깨끗한 재구성으로 오인되지 않도록 거부를 구별되게 보고하십시오.
  • 활성 콘텐츠가 제거됩니다. 스크립트, 실행 액션, 문서 수준 스크립트 네임 트리, 임베드된 파일, 리치 미디어 등의 표면이 제거됩니다 — 뷰어가 그렇지 않으면 실행했을 바로 그 액션입니다(ISO 32000-2 §12.6.4 ECMAScript 액션; 실행 액션; 문서 수준 스크립트 §7.7.4).
  • 서명은 재구성으로 무효화됩니다. 재구성이 바이트 레이아웃을 변경하므로 원본 서명은 더 이상 검증될 수 없습니다. 서명 객체는 오해를 일으키는 채로 제자리에 남겨지지 않고 제거됩니다.
  • 설계상 손실이 있습니다. Factur-X 같은 인보이스 첨부를 포함한 임베드된 파일 페이로드는 해당 위협 유형이 제거될 때 함께 제거됩니다. CDR은 보존 계층이 아니라 보안 투영입니다.

이 페이지는 문서 보안에 관한 것입니다. 모든 규범적 출처는 의역되었습니다. 규범 텍스트는 재현하지 않습니다.

  • 파싱 실패. 파싱할 수 없는 문서는 부분 재구성이 아니라 파싱 오류 사유와 함께 수용되지 않음 결과를 산출합니다.
  • 한도 초과 입력. 결과는 한도별 사유와 함께 수용되지 않음으로 보고됩니다. 재구성된 바이트는 비어 있습니다.
  • 파싱 불가능한 객체. 파싱할 수 없는 객체는 조용히 유지되지 않고 잠재적 우회로 취급되어 제거됩니다.
  • 최선 노력 페이지 수. 페이지 수 수용 검사는 최선 노력입니다. 잘못된 카탈로그가 파이프라인을 충돌시키지는 않지만, 객체 수 및 스트림 한도는 여전히 적용됩니다.

이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만을 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 표, 런북 파일명, 티켓 접두사는 범위를 벗어납니다.