Bảo mật và vận hành Artisan
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Cầu nối kết xuất HTML xử lý nội dung có thể không đáng tin cậy bên trong Chrome, phía sau hai rào cản mạng độc lập và một chính sách nội dung nghiêm ngặt. Sandbox cấp hệ điều hành của Chrome là một biện pháp kiểm soát riêng biệt, tùy chọn, với những giới hạn rõ ràng. Trang này ghi lại ranh giới đó và không tuyên bố rằng ranh giới này là tuyệt đối.
Tổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”Một lần kết xuất là một lần thực thi yêu cầu phía máy chủ: ứng dụng của bạn giao HTML cho một công cụ trình duyệt vốn có thể nạp tài nguyên theo mặc định. Khi đầu vào không đáng tin cậy điều khiển một lần nạp ra bên ngoài, rủi ro phát sinh là giả mạo yêu cầu phía máy chủ (SSRF): mục Common Weakness Enumeration (CWE) CWE-918 định nghĩa đó là việc máy chủ lấy nội dung của một URL được cung cấp mà không bảo đảm đầy đủ rằng yêu cầu đi đến đúng đích mong đợi. SSRF (CWE-918) là một điểm yếu thuộc CWE Top 25. Open Worldwide Application Security Project (OWASP) Application Security Verification Standard (ASVS) yêu cầu bạn kiểm soát các yêu cầu ra bên ngoài từ những thành phần máy chủ thay vì để chúng diễn ra ngầm định. OWASP SSRF Prevention Cheat Sheet coi việc chặn ở tầng mạng đối với các lệnh gọi đến những đích tùy ý là biện pháp kiểm soát mạnh. Cách tiếp cận mạng từ chối theo mặc định dưới đây là cách cầu nối đáp ứng yêu cầu đó. National Institute of Standards and Technology (NIST) Special Publication (SP) 800-53 SC-7 mô tả cùng một nguyên tắc ranh giới: từ chối tất cả và chỉ cho phép theo ngoại lệ, được cầu nối áp dụng ở tầng truyền tải.
Lưu trú dữ liệu và các biện pháp giảm thiểu PII
Phần tiêu đề “Lưu trú dữ liệu và các biện pháp giảm thiểu PII”HTML được truyền vào cầu nối được xử lý hoàn toàn trong tiến trình và trong phiên bản Chrome cục bộ. Cầu nối không tự thực hiện bất kỳ lệnh gọi mạng ra ngoài nào và chặn Chrome thực hiện mọi lệnh gọi như vậy (xem mô hình mạng bên dưới), nên nội dung đầu vào không rời khỏi máy chủ thông qua bộ kết xuất. Thông tin định danh cá nhân (PII) trong đầu vào được kết xuất vào đầu ra Portable Document Format (PDF) mà bạn tạo ra, vì vậy hãy áp dụng cho đầu ra các biện pháp kiểm soát lưu trú giống như với đầu vào. Cầu nối không lưu giữ đầu vào hay đầu ra xuống đĩa; việc lưu giữ là trách nhiệm của bên gọi.
Đo lường từ xa an toàn và làm sạch nhật ký
Phần tiêu đề “Đo lường từ xa an toàn và làm sạch nhật ký”ChromeHtmlRenderer và BrowserPool nhận một LoggerInterface tùy chọn theo PHP Standard Recommendation (PSR)-3. Cầu nối chỉ ghi nhật ký siêu dữ liệu vận hành: độ dài byte đầu vào, chiều rộng và chiều cao đích, độ dài byte đầu ra, chiều cao nội dung đo được, sự kiện khởi chạy trình duyệt với đường dẫn nhị phân đã cấu hình, thông báo khởi động lại kèm số lần kết xuất, và các sự kiện đóng. Cầu nối không ghi nhật ký nội dung HTML, byte đã kết xuất hay văn bản trích xuất. Điều này phù hợp với hướng dẫn của NIST SP 800-92 về việc ghi nhật ký các sự kiện vận hành trong khi giữ dữ liệu nhạy cảm bên ngoài nhật ký. Đường dẫn nhị phân được ghi nhật ký. Hãy coi đó là siêu dữ liệu triển khai không nhạy cảm. Các bài kiểm thử xác nhận hình dạng của các lệnh gọi ghi nhật ký trong tests/Unit/Artisan/ChromeHtmlRendererTest.php::renderLogsDebugWithSizeWidthHeightAndPdfSize và tests/Unit/Artisan/BrowserPoolTest.php::getBrowserLogsInfoOnLaunchWithBinaryPath.
Mô hình cô lập mạng (phòng thủ theo lớp)
Phần tiêu đề “Mô hình cô lập mạng (phòng thủ theo lớp)”Cầu nối áp dụng hai rào cản độc lập để việc vượt qua một lớp không làm lộ máy chủ:
-
Content-Security-Policy. Mỗi lần kết xuất được bọc bởi
ChromeSecurityPolicy::wrapHtml()trong một tài liệu mang theo:default-src 'none'; style-src 'unsafe-inline'; img-src data:;base-uri 'none'; form-action 'none'; frame-ancestors 'none';navigate-to 'none';Chỉ thị Content Security Policy (CSP)
default-src 'none'từ chối tất cả các nguồn gốc tài nguyên.img-src data:chỉ cho phép ảnh nội tuyến.navigate-to 'none'chặn điều hướng phía máy khách.style-src 'unsafe-inline'là nới lỏng duy nhất cần thiết để ChromeprintToPDFáp dụng các kiểu nội tuyến. Điều này được xác minh trongsrc/Artisan/ChromeSecurityPolicy.phpvà được khẳng định bởiChromeSecurityPolicyTest::wrapHtmlIncludesNavigationCspDirectives. -
Chặn truyền tải Chrome DevTools Protocol (CDP). Trước khi nội dung được nạp,
ChromeHtmlRendererphát raNetwork.enablerồi sau đóNetwork.setBlockedURLsvới mẫu['*']. Điều này chặn mọi URL tài nguyên con tại tầng truyền tải Chrome DevTools Protocol, độc lập với CSP. Điều này được xác minh trongsrc/Artisan/ChromeHtmlRenderer::blockAllNetworkRequests()và được khẳng định bởiChromeHtmlRendererTest::renderAutoFitsHeightAndBlocksNetworkRequests(bài kiểm thử kiểm tra đúng thứ tự phương thức CDP và tham số['urls' => ['*']]). Đây là biện pháp chặn ở tầng mạng mà hướng dẫn SSRF của OWASP khuyến nghị là biện pháp kiểm soát mạnh nhất, và cũng là một dạng từ chối tất cả ở cấp truyền tải, nhất quán với NIST SP 800-53 SC-7.
Kết quả: một URL <img> từ xa, bảng định kiểu, phông chữ, tập lệnh hay iframe trong đầu vào sẽ không được nạp. Cầu nối không hiện thực danh sách miền cho phép hay bộ lọc IP riêng tư vì không cần đến chúng: nó hoàn toàn không cho phép bất kỳ lệnh nạp tài nguyên con ra bên ngoài nào.
Lưu ý về sai lệch: docblock của
nextpdf/coretrênwriteHtmlChrome()nói rằng Chrome “sẽ nạp tài nguyên bên ngoài” và khuyên cấu hình một chính sách để “chặn các dải IP riêng tư và giới hạn các miền được phép.” Điều đó mô tả một mô hình danh sách cho phép có thể cấu hình.ChromeSecurityPolicyđược phát hành kèm Artisan không cung cấp danh sách cho phép; nó chặn tất cả các yêu cầu tài nguyên con một cách vô điều kiện. Mã nguồn, chứ không phải docblock của core, mới là nguồn có thẩm quyền. Sai lệch này được ghi nhận để chuyển cho nhóm tài liệu của core.
Kiểm định đầu vào (trước khi vào Chrome)
Phần tiêu đề “Kiểm định đầu vào (trước khi vào Chrome)”ChromeSecurityPolicy::validate() chạy trước khi cầu nối liên hệ với Chrome và từ chối:
| Kiểm tra | Giới hạn | Lý do |
|---|---|---|
| Kích thước HTML | > maxHtmlSize (mặc định 5 MB) | Giới hạn cạn kiệt tài nguyên (tiêu thụ tài nguyên không kiểm soát, thuộc CWE Top 25) |
| URI dữ liệu base64 | nhóm bắt >= 13_000_000 byte | Giới hạn chống bom giải nén |
<meta http-equiv="refresh"> | bất kỳ (không phân biệt hoa thường, single/double) | Chặn các chuyển hướng phía máy khách đến các điểm cuối nội bộ, một vector điều hướng SSRF |
Việc chặn meta-refresh là một biện pháp gia cố SSRF tường minh. Nếu không có biện pháp này, HTML do kẻ tấn công kiểm soát có thể chuyển hướng Chrome đến một điểm cuối siêu dữ liệu đám mây trước khi printToPDF. Hành vi tại ranh giới được khẳng định xuyên suốt ChromeSecurityPolicyTest (validateThrowsOnOversizedHtml, validateRejectsMetaRefreshRedirect, validateRejectsMetaRefreshCaseInsensitive, validateRejectsMetaRefreshWithSingleQuotes, validateRejectsOversizedBase64DataUri, validateRejectsBase64DataUriAtExactThreshold).
Ngoài ra, ChromeSecurityPolicy::wrapHtml() loại bỏ </style> khỏi defaultCss trước khi tiêm vào, nhằm ngăn việc thoát khỏi khối style để vào ngữ cảnh tập lệnh (được khẳng định bởi ChromeSecurityPolicyTest::wrapHtmlStripsStyleClosingTagsFromDefaultCss).
Ranh giới sandbox của Chrome — được nêu tường minh
Phần tiêu đề “Ranh giới sandbox của Chrome — được nêu tường minh”Sandbox cấp hệ điều hành của Chrome là một biện pháp kiểm soát riêng biệt với các rào cản mạng ở trên, và cầu nối không bảo đảm biện pháp đó.
- Theo mặc định,
noSandboxlàfalse, nên Chrome khởi chạy với sandbox riêng được bật. Cầu nối không hiện thực sandbox đó; nó dựa vào sandbox của tệp nhị phân Chrome, vốn phụ thuộc vào sự hỗ trợ của nhân hệ điều hành máy chủ. - Đặt
noSandbox: truesẽ khởi chạy Chrome với--no-sandbox. Điều này loại bỏ sandbox cô lập tiến trình của Chrome. Tùy chọn này được cung cấp cho các container nơi sandbox không thể khởi tạo. Đó là một sự suy giảm thực sự về mức độ cô lập: khi bộ kết xuất bị xâm phạm, sandbox của Chrome sẽ không còn ngăn chặn được nữa. - Các rào cản mạng của cầu nối (CSP + chặn CDP) vẫn có hiệu lực dù sandbox có được bật hay không, nhưng chúng không thay thế cho cô lập tiến trình. Hướng dẫn về đặc quyền tối thiểu của OWASP ASVS được áp dụng: chạy Chrome với tư cách người dùng không phải root, trong một container bị ràng buộc, chỉ dùng
noSandboxở nơi không thể tránh khỏi, và coi một triển khai--no-sandboxnhư một yêu cầu mức tin cậy cao hơn đối với đầu vào.
Tài liệu này không tuyên bố rằng cầu nối “an toàn theo mặc định” hay “chống giả mạo”. Tài liệu cũng không tuyên bố rằng việc tắt sandbox là an toàn. Nó nêu ra các biện pháp kiểm soát đang tồn tại và điểm dừng của chúng. Việc cấp phát một container có khả năng dùng sandbox được trình bày trên trang /integrations/artisan/chrome-renderer-setup/.
Các chế độ lỗi
Phần tiêu đề “Các chế độ lỗi”Các chế độ lỗi này được liệt kê từ src/Artisan/Exception/ và mã render/transport:
| Điều kiện | Biểu lộ dưới dạng | Nguồn |
|---|---|---|
chrome-php/chrome không có | ChromeNotAvailableException (kèm lệnh cài đặt) | BrowserPool::getBrowser() |
HTML vượt quá maxHtmlSize | RuntimeException (“exceeds maximum allowed size”) | ChromeSecurityPolicy::validate() |
| URI dữ liệu base64 quá cỡ | RuntimeException (“oversized base64 data URI”) | ChromeSecurityPolicy::validate() |
| Meta-refresh bị cấm | RuntimeException (“forbidden meta refresh redirect”) | ChromeSecurityPolicy::validate() |
| Chrome khởi chạy / hết thời gian chờ / sập | ChromeRenderException (bọc nguyên nhân gốc) | ChromeHtmlRenderer::render() |
| Chrome trả về PDF rỗng | ChromeRenderException (“returned empty data”) | ChromeHtmlRenderer::render() |
| Trang không có luồng nội dung | PdfParseException | PageImporter::import() |
Nếu ChromeRenderException được phát ra trong quá trình kết xuất, nó được ném lại nguyên trạng. Bất kỳ Throwable nào khác đều được bọc thành ChromeRenderException, đồng thời giữ lại ngoại lệ trước đó (được khẳng định bởi ChromeHtmlRendererTest::renderRethrowsChromeRenderExceptionWithoutWrapping và ::renderWrapsUnexpectedThrowablesWithChromeRenderException). Trang Chrome luôn được đóng trong một khối finally, kể cả khi gặp lỗi.
Giới hạn tài nguyên
Phần tiêu đề “Giới hạn tài nguyên”- Kích thước đầu vào:
maxHtmlSize(mặc định 5 MB) và giới hạn 13 MB cho URI dữ liệu base64. - Thời gian:
renderTimeoutgiây giới hạn cả việc nạp nội dung lẫn các lệnh gọi đồng bộ CDP. Các lệnh điều khiển CDP dùng một thời gian chờ cố định là 5 giây. - Tiến trình:
BrowserPoolkhởi động lại Chrome sau mỗi 100 lần kết xuất để giới hạn mức tăng bộ nhớ và đóng tiến trình khi gọiclose()/ khi bị hủy.
Đây là các ngưỡng giới hạn, không phải hạn ngạch. Với bất kỳ đường dẫn nào nhận đầu vào không đáng tin cậy, hãy vẫn dùng một giới hạn tài nguyên ở cấp máy chủ (cgroup, ulimit, ngân sách yêu cầu), nhất quán với hướng dẫn về tiêu thụ tài nguyên của CWE Top 25.
Các móc quan sát
Phần tiêu đề “Các móc quan sát”Tiêm một logger PSR-3 để ghi lại lúc bắt đầu kết xuất (kích thước, chiều rộng, chiều cao), lúc hoàn tất kết xuất (kích thước đầu ra, chiều cao nội dung), lúc khởi chạy trình duyệt (đường dẫn nhị phân), lúc khởi động lại trình duyệt (số lần kết xuất), và lúc đóng trình duyệt (số lần kết xuất). Đây là những sự kiện duy nhất được phát ra, và chúng không mang theo nội dung tải. Hãy dùng chúng cho các mục tiêu mức dịch vụ (SLO) về độ trễ và cảnh báo về tỷ lệ khởi động lại.
Tính tuân thủ
Phần tiêu đề “Tính tuân thủ”| Tuyên bố | Tham chiếu | clause_id | reference_id |
|---|---|---|---|
| Các yêu cầu ra bên ngoài từ những thành phần máy chủ phải được kiểm soát | OWASP ASVS 5.0 | § (SSRF/kiểm soát yêu cầu ra ngoài) | |
| SSRF = máy chủ lấy một URL được cung cấp mà không kiểm định đích đến | CWE Top 25 2025 (CWE-918) | cwe_top25_2025#x28.x2.p2 | |
| SSRF (CWE-918) là một điểm yếu thuộc CWE Top 25 | CWE Top 25 2025 | cwe_top25_2025#x1.p73 | |
| Tiêu thụ tài nguyên không kiểm soát là một điểm yếu thuộc CWE Top 25 | CWE Top 25 2025 (CWE-400) | cwe_top25_2025#x19.x2.p2 | |
| Bảo vệ ranh giới từ chối theo mặc định (cho phép theo ngoại lệ) | NIST SP 800-53 Rev 5 SC-7 | SC-7 | |
| Chặn ở tầng mạng các lệnh gọi đến những đích tùy ý là biện pháp kiểm soát SSRF mạnh | OWASP Cheat Sheet Series (SSRF Prevention §Network layer) | owasp_cheatsheet_series#x132.x2 | |
| Bảo vệ các thành phần nạp URL trước SSRF | OWASP Cheat Sheet Series | § (phòng chống SSRF, công cụ nạp URL) | |
| Cô lập việc kết xuất nội dung không đáng tin cậy, đặc quyền tối thiểu | OWASP ASVS 5.0 | § (sandbox / đặc quyền tối thiểu) | |
| Ghi nhật ký các sự kiện vận hành; giữ nội dung tải ra khỏi nhật ký | NIST SP 800-92 | § (hướng dẫn về nội dung nhật ký) |
Các trích dẫn được lấy thông qua công cụ tuân thủ của NextPDF (bản kê khai kho ngữ liệu 1d05b7c4…d790b6); văn bản điều khoản được diễn giải lại, không bao giờ trích dẫn nguyên văn.
Mô hình mối đe dọa
Phần tiêu đề “Mô hình mối đe dọa”| Mối đe dọa | Biện pháp kiểm soát | Rủi ro còn lại |
|---|---|---|
| SSRF qua tài nguyên con từ xa | CSP default-src 'none' + CDP setBlockedURLs('*') | Một lỗi của công cụ Chrome có thể vượt qua cả hai rào cản (phòng thủ theo lớp làm giảm rủi ro, nhưng không loại bỏ nó) |
| SSRF qua điều hướng meta-refresh | Việc kiểm định trước khi vào Chrome từ chối thẻ này | Một vector điều hướng mới không khớp với mẫu |
| Cạn kiệt tài nguyên | Giới hạn kích thước đầu vào + giới hạn base64 + thời gian chờ + khởi động lại sau 100 lần kết xuất | Không có hạn ngạch theo từng máy chủ; hãy kết hợp với cgroup/ulimit |
| Tiến trình bộ kết xuất bị xâm phạm | Sandbox của Chrome khi được bật | noSandbox: true loại bỏ hoàn toàn biện pháp kiểm soát này |
| Thoát khỏi khối style / tiêm mã | </style> được loại bỏ trong defaultCss; CSP chặn tập lệnh | Tiêm mã thông qua một vector trong tương lai không bị loại bỏ |
Hành vi ở chế độ FIPS
Phần tiêu đề “Hành vi ở chế độ FIPS”Cầu nối không thực hiện thao tác mật mã nào. Nó tạo ra các byte PDF thông qua Chrome và nhúng chúng vào. Việc ký, mã hóa và hành vi ở chế độ Federal Information Processing Standards (FIPS) là những vấn đề thuộc core/Premium và không bị Artisan tác động.
Xem thêm
Phần tiêu đề “Xem thêm”- /integrations/artisan/configuration/
- /integrations/artisan/chrome-renderer-setup/
- /integrations/artisan/troubleshooting/
- /integrations/artisan/production-usage/
- /integrations/artisan/overview/