Mã hóa PDF và hạn chế quyền
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Công thức này mã hóa tài liệu bằng trình xử lý bảo mật chuẩn Advanced Encryption Standard (AES)-256. Bạn đặt mật khẩu người dùng (cần thiết để mở), mật khẩu chủ sở hữu (toàn quyền) và bitmask quyền để hạn chế các thao tác. Hãy xem các quyền đó là phụ thuộc vào sự hợp tác của trình đọc: mã hóa mang lại tính bảo mật, không phải tính toàn vẹn, và chỉ phần mềm hợp tác mới tôn trọng các bit quyền. Công thức này bám theo examples/22-protection.php.
Ranh giới tin cậy (hãy ghi nhớ điều này trong mọi tuyên bố về quyền). Mã hóa PDF bảo vệ tính bảo mật của nội dung khỏi các bên không có mật khẩu (ISO 32000-2 §7.6). Nó không bảo vệ tính toàn vẹn: nó không phát hiện hoặc ngăn chặn việc sửa đổi. Mục quyền
Plà một tập cờ không dấu 32 bit yêu cầu trình đọc tuân thủ tôn trọng các hạn chế; nó không phải là một cơ chế kiểm soát truy cập. Một công cụ không tuân thủ, hoặc bất kỳ công cụ nào dùng với mật khẩu chủ sở hữu, đều có thể thực hiện mọi thao tác “bị từ chối”. Đừng mô tả PDF đã mã hóa là “an toàn”, “chống giả mạo” hay “chống sao chép”.
Cài đặt
Phần tiêu đề “Cài đặt”composer require nextpdf/core:^3Bật phần mở rộng PHP openssl. Trình mã hóa AES-256 dùng phần mở rộng này cho mật mã và dẫn xuất khóa.
Tổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”Các mã V/R của từ điển mã hóa chọn trình xử lý bảo mật chuẩn (ISO 32000-2 §7.6). NextPDF cung cấp Aes256Encryptor, triển khai bộ lọc mật mã AESV3 ở bản sửa đổi 6 của trình xử lý bảo mật (V=5/R=6). Nó dùng khóa mã hóa tệp 256 bit ngẫu nhiên, dẫn xuất khóa bằng băm lặp có muối (Algorithm 2.B), và mã hóa từng đối tượng bằng AES-256-CBC với một vector khởi tạo ngẫu nhiên. Cipher Block Chaining (CBC) là một chế độ bảo mật (NIST SP 800-38A). Các vector khởi tạo của nó phải không thể đoán trước.
Mỗi đối tượng và mỗi lần chạy đều có vector khởi tạo mới, nên các byte thô khác nhau giữa các lần chạy. Do đó hồ sơ khả năng tái lập là structural. Trước khi so sánh hai lần chạy, bộ kiểm thử chuẩn hóa IV mã hóa, thứ tự đối tượng và /ID trong trailer. Hồ sơ này nghiêm ngặt hơn hồ sơ của công thức không dùng mã hóa.
Bitmask quyền thiết lập mục P. Bit 3 cấp quyền in, và bit 6 cấp quyền annotation/form-fill. Giá trị là đại lượng không dấu 32 bit theo đặc tả.
Bề mặt API
Phần tiêu đề “Bề mặt API”NextPDF\Core\Concerns\HasSecurity (được trộn vào Document):
setEncryption(#[SensitiveParameter] string $userPassword, #[SensitiveParameter] string $ownerPassword = '', int $permissions = -1): static— cấu hình mã hóa của trình xử lý chuẩn AES-256.permissions = -1cấp tất cả các quyền. KhiownerPasswordđể trống, mật khẩu người dùng được dùng lại làm mật khẩu chủ sở hữu. Hãy gọi trướcaddPage().getEncryptor(): ?Aes256Encryptor— trình mã hóa đã được cấu hình, hoặcnull.useAesGcm(?bool $enabled = true): static— bật dùng AES-256-GCM theo ISO/TS 32003; sẽ ném ngoại lệ nếu OpenSSL/libsodium của máy chủ không cung cấp mật mã đó.
Cả hai tham số mật khẩu đều được đánh dấu #[SensitiveParameter], nên PHP sẽ che chúng khỏi stack trace.
Các bit quyền (mục P, các bit thấp 3–6 thường dùng):
| Bit | Giá trị | Thao tác |
|---|---|---|
| 3 | 4 | In tài liệu |
| 4 | 8 | Sửa đổi nội dung tài liệu |
| 5 | 16 | Sao chép / trích xuất văn bản và đồ họa |
| 6 | 32 | Thêm hoặc sửa đổi chú thích và điền các trường biểu mẫu |
Mẫu mã — bắt đầu nhanh
Phần tiêu đề “Mẫu mã — bắt đầu nhanh”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Confidential Memo');
// Grant printing only (bit 3 = 4). MUST run before addPage().$doc->setEncryption( userPassword: 'open-me', ownerPassword: 'owner-secret', permissions: 4,);
$doc->addPage();$doc->setFont('helvetica', '', 12);$doc->cell(0, 10, 'Encrypted with AES-256; printing allowed only.', newLine: true);
$doc->save(__DIR__ . '/confidential.pdf');echo "Wrote confidential.pdf\n";Mẫu mã — sản xuất
Phần tiêu đề “Mẫu mã — sản xuất”Ví dụ đầy đủ bên dưới phản chiếu examples/22-protection.php và ghi vào NEXTPDF_COOKBOOK_OUTPUT cho bộ kiểm thử.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$userPassword = 'demo';$ownerPassword = 'admin';
// Grant ONLY printing (bit 3 = 4); deny copy/modify/annotate.$permissions = 4;
$doc = Document::createStandalone();$doc->setTitle('Encrypted Document — Restricted Permissions');$doc->setAuthor('NextPDF Example');
// setEncryption() MUST be called before addPage().$doc->setEncryption( userPassword: $userPassword, ownerPassword: $ownerPassword, permissions: $permissions,);
$doc->addPage();$doc->setFont('helvetica', 'B', 20);$doc->cell(0, 14, 'Encrypted PDF Document', newLine: true);$doc->ln(8);
$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'This document is protected with AES-256 encryption ' . '(standard security handler, revision 6). The user password is required ' . 'to open it; the owner password grants full access. The permission ' . 'bits below are honoured by conforming readers only.');$doc->ln(5);
$permissionTable = [ ['Bit 3 (4)', 'Printing', 'ALLOWED'], ['Bit 4 (8)', 'Content modification', 'DENIED'], ['Bit 5 (16)', 'Text copying / extraction', 'DENIED'], ['Bit 6 (32)', 'Annotations / form fields', 'DENIED'],];$doc->setFont('helvetica', 'B', 10);$doc->cell(30, 7, 'Flag');$doc->cell(60, 7, 'Operation');$doc->cell(0, 7, 'Status', newLine: true);foreach ($permissionTable as [$bit, $operation, $status]) { $doc->setFont('courier', '', 9); $doc->cell(30, 7, $bit); $doc->setFont('helvetica', '', 10); $doc->cell(60, 7, $operation); $doc->setFont('helvetica', 'B', 10); $doc->cell(0, 7, $status, newLine: true);}
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false ? $out : __DIR__ . '/encrypted.pdf');
echo "Wrote encrypted PDF (AES-256, printing only)\n";Kết quả mong đợi:
Wrote encrypted PDF (AES-256, printing only)Khi bạn mở tệp, trình đọc sẽ nhắc nhập mật khẩu. Mật khẩu người dùng mở tệp với tập quyền hạn chế. Mật khẩu chủ sở hữu mở tệp với toàn quyền truy cập.
Trường hợp đặc biệt & lưu ý
Phần tiêu đề “Trường hợp đặc biệt & lưu ý”- Thứ tự gọi.
setEncryption()gọi sauaddPage()sẽ không mã hóa hồi tố nội dung trước đó. Hãy cấu hình mã hóa trước; engine mã hóa phần thân của từng đối tượng khi đối tượng đó được ghi ra. - Mặc định của mật khẩu chủ sở hữu. Khi để trống mật khẩu chủ sở hữu, engine sẽ dùng lại mật khẩu người dùng làm mật khẩu chủ sở hữu. Trên thực tế, như vậy không còn vai trò đặc quyền riêng. Hãy đặt hai mật khẩu khác nhau khi hai vai trò cần tách biệt.
- Ngữ nghĩa quyền chỉ mang tính tư vấn. Chỉ các trình đọc tuân thủ mới tôn trọng các bit. Chúng không được thực thi bằng mật mã: một công cụ không tuân thủ, hoặc bất kỳ công cụ nào dùng với mật khẩu chủ sở hữu, đều có thể thực hiện các thao tác bị hạn chế. Hãy coi quyền là tín hiệu chính sách gửi tới phần mềm hợp tác, không bao giờ là cơ chế kiểm soát truy cập có thể chống chịu một bên quyết tâm.
- Không bảo đảm tính toàn vẹn. Mã hóa cung cấp tính bảo mật, không phải tính toàn vẹn. Kẻ tấn công không có mật khẩu không thể đọc nội dung, nhưng bản thân định dạng không phát hiện được việc giả mạo. Việc bảo vệ tính toàn vẹn cần một cơ chế riêng, chẳng hạn chữ ký số hoặc document MAC theo ISO/TS 32004.
- Xung đột với PDF/A. PDF/A cấm khóa trailer
Encrypt. GọisetEncryption()trên tài liệu PDF/A, ở bất kỳ thứ tự nào, đều ném ngoại lệ không tương thích. - Bật dùng AES-256-GCM.
useAesGcm()chọn mã hóa hàng loạt GCM theo ISO/TS 32003 khi OpenSSL hoặc libsodium của máy chủ cung cấp nó. Nếu không, nó némInvalidConfigException. Nó không tương thích với PDF/A vì cùng lý do đó. - Mã hóa khóa công khai chưa được nối dây.
setPublicKeyEncryption()cố định bề mặt API, nhưngsave()ném ngoại lệ cho đến khi phần nối dây của trình ghi hoàn tất (một lỗi đã biết). Đừng dùng nó trong sản xuất trên Core.
Hiệu năng
Phần tiêu đề “Hiệu năng”Việc dẫn xuất khóa thực hiện băm lặp của Algorithm 2.B một lần cho mỗi tài liệu. AES-256-CBC trên từng đối tượng có chi phí tuyến tính theo kích thước phần thân đối tượng. Với các tài liệu thông thường, chi phí vẫn nằm trong ngân sách 1.500 ms / 64 MB. Các tài liệu rất lớn phải chịu chi phí thông lượng AES cho mỗi đối tượng. Galois/Counter Mode (GCM) với AES-NI nhanh hơn trên các máy chủ hỗ trợ.
Lưu ý bảo mật
Phần tiêu đề “Lưu ý bảo mật”- Chỉ tính bảo mật. Nhắc lại ranh giới tin cậy: mã hóa giữ nội dung khỏi các bên không có mật khẩu. Nó không chứng minh tệp chưa bị thay đổi, và các bit quyền phụ thuộc vào sự hợp tác của trình đọc.
- Độ mạnh mật khẩu do bạn quyết định. Trình xử lý chỉ mạnh tương ứng với độ mạnh của mật khẩu. Một khi ai đó có được tệp, mật khẩu người dùng yếu có thể bị bẻ khóa ngoại tuyến; định dạng không thể giới hạn tốc độ thử mật khẩu.
- Mật khẩu chủ sở hữu là một khóa chính. Bất kỳ ai có mật khẩu chủ sở hữu đều vượt qua mọi hạn chế. Hãy coi nó như một thông tin xác thực gốc; đừng bao giờ gửi nó kèm tài liệu hay ghi nó vào nhật ký.
#[SensitiveParameter]là phòng thủ theo chiều sâu. Nó che các mật khẩu khỏi stack trace của PHP, nhưng bạn vẫn phải giữ chúng ngoài nhật ký, thông báo ngoại lệ và báo cáo sự cố của riêng bạn.
Lưu trú dữ liệu & giảm thiểu PII
Phần tiêu đề “Lưu trú dữ liệu & giảm thiểu PII”Thư viện thực hiện mã hóa trong tiến trình. Nó không truyền tài liệu hay mật khẩu đi đâu cả. Engine không ghi mật khẩu, khóa hay byte tài liệu nào ra đĩa, ngoại trừ kết quả đã mã hóa mà bạn lưu. Vị trí của tệp kết quả và cách giữ mật khẩu là các vấn đề triển khai mà người tích hợp tự chịu trách nhiệm. Thư viện không đưa ra bảo đảm nào về lưu trú dữ liệu. Nếu tài liệu ở dạng văn bản gốc chứa dữ liệu cá nhân, dữ liệu đó chỉ được bảo vệ ngang với mật khẩu yếu nhất và lưu ý ở trên về trình đọc hợp tác. Mã hóa không thay thế cho việc giảm thiểu thông tin nhận dạng cá nhân (PII) mà bạn đưa vào tài liệu.
Telemetry an toàn & làm sạch nhật ký
Phần tiêu đề “Telemetry an toàn & làm sạch nhật ký”Quá trình mã hóa phát ra một EncryptionAppliedEvent chỉ chứa tên thuật toán (AES-256) và ba giá trị boolean tóm tắt print/copy/modify có được phép hay không — không bao giờ đưa mật khẩu, khóa, muối hay IV nào lên sự kiện (src/Event/Security/EncryptionAppliedEvent.php). Đường dẫn OpenTelemetry định tuyến các thuộc tính span qua một bộ làm sạch theo allowlist (src/Telemetry/AttributeSanitizer.php) loại bỏ vô điều kiện mật khẩu và đường dẫn tệp; chỉ các khóa trong allowlist với giá trị vô hướng mới được giữ lại. Đừng thêm mật khẩu hay dữ liệu khóa vào span, nhật ký hay thông báo ngoại lệ trong mã tích hợp của riêng bạn. Các dấu #[SensitiveParameter] bảo vệ stack trace, nhưng không bảo vệ các chuỗi do bạn tự dựng.
Mô hình mối đe dọa
Phần tiêu đề “Mô hình mối đe dọa”Trong phạm vi: kẻ thù có được tệp đã mã hóa nhưng không có mật khẩu. Tùy vào độ mạnh mật khẩu, họ không thể đọc nội dung, và tệp không rò rỉ văn bản gốc. Ngoài phạm vi: kẻ thù có mật khẩu người dùng hoặc chủ sở hữu; trình đọc không tuân thủ bỏ qua các bit quyền; bẻ khóa brute-force ngoại tuyến đối với mật khẩu yếu; phát hiện giả mạo (mã hóa cung cấp tính bảo mật, không phải tính toàn vẹn); các kênh phụ trong bản dựng OpenSSL của máy chủ; và việc lưu giữ khóa, hoàn toàn thuộc trách nhiệm của người tích hợp. Việc ghi lại các mối đe dọa này không khẳng định rằng không có lỗ hổng.
Hành vi ở chế độ FIPS
Phần tiêu đề “Hành vi ở chế độ FIPS”Bản dựng OpenSSL của máy chủ cung cấp các nguyên hàm mật mã, nên trạng thái FIPS là thuộc tính của máy chủ, không phải thiết lập của thư viện. CryptoCapabilities::detectFipsMode() trả về một FipsModeDetection ba trạng thái (src/Security/FipsModeDetection.php): FIPS_ACTIVE, FIPS_ABSENT, hoặc INDETERMINATE. Phần mở rộng openssl của PHP không cung cấp binding nào cho mô hình provider của OpenSSL 3, nên việc dò tìm chỉ mang tính best-effort. INDETERMINATE được xử lý là “FIPS chưa được chứng minh” (fail-closed), và được phân biệt trong telemetry để người vận hành có thể hành động. NextPDF không tuyên bố đạt chứng nhận FIPS 140; việc chạy trên OpenSSL đã được FIPS xác nhận là trách nhiệm của người vận hành, và kết quả dò tìm chỉ mang tính tư vấn.
Tuân thủ
Phần tiêu đề “Tuân thủ”| Phát biểu | Tiêu chuẩn | Điều khoản | reference_id |
|---|---|---|---|
Mã V của từ điển mã hóa chọn thuật toán mã hóa. | ISO 32000-2 | §7.6 | |
Mục CFM đặt tên phương thức bộ lọc mật mã AESV3. | ISO 32000-2 | §7.6 | |
Mục P là một đại lượng quyền truy cập không dấu 32 bit. | ISO 32000-2 | §7.6 | |
| Bit quyền 3 điều khiển việc in. | ISO 32000-2 | §7.6 | |
| Bit quyền 6 điều khiển chú thích / điền biểu mẫu. | ISO 32000-2 | §7.6 | |
| Mã hóa bảo vệ nội dung khỏi truy cập trái phép (tính bảo mật). | ISO 32000-2 | §7.6 | |
| Việc dẫn xuất khóa của bản sửa đổi 6 dùng băm lặp có muối (Algorithm 2.B). | ISO 32000-2 | §7.6 | |
| CBC là một chế độ bảo mật (không phải chế độ toàn vẹn). | NIST SP 800-38A | §6.2 | |
| Các vector khởi tạo CBC phải không thể đoán trước. | NIST SP 800-38A | Phụ lục. C |
NextPDF triển khai các điều khoản được trích dẫn. Nó không khẳng định tuân thủ ISO 32000-2 toàn diện, đạt chứng nhận FIPS 140, hay bất kỳ bảo đảm pháp lý hoặc hợp đồng nào về tính bảo mật. “Hỗ trợ trình xử lý bảo mật chuẩn” không phải là chứng nhận bảo mật cho triển khai của bạn. Mức bảo đảm đó phụ thuộc vào việc lưu giữ mật khẩu và chính sách của bên xác minh, nằm ngoài thư viện.