Keamanan dan operasi Artisan
Sekilas pandang
Bagian berjudul “Sekilas pandang”Jembatan ini merender HTML yang mungkin tidak tepercaya di dalam Chrome, dengan dua penghalang jaringan independen dan kebijakan konten yang ketat. Sandbox tingkat sistem operasi milik Chrome merupakan kontrol terpisah dan opsional dengan batasan yang eksplisit. Halaman ini mendokumentasikan batasan tersebut, tanpa mengklaim bahwa batasnya absolut.
Gambaran konseptual
Bagian berjudul “Gambaran konseptual”Sebuah render merupakan eksekusi permintaan di sisi server: aplikasi Anda menyerahkan HTML ke mesin peramban yang secara baku dapat mengambil sumber daya. Ketika input yang tidak tepercaya mengendalikan pengambilan ke luar, risikonya adalah server-side request forgery (SSRF): entri Common Weakness Enumeration (CWE) CWE-918 mendefinisikannya sebagai kondisi ketika server mengambil konten dari URL yang diberikan tanpa memastikan secara memadai bahwa permintaan tersebut mencapai tujuan yang diharapkan. SSRF (CWE-918) adalah kelemahan CWE Top 25. Open Worldwide Application Security Project (OWASP) Application Security Verification Standard (ASVS) mengharuskan Anda mengendalikan permintaan keluar dari komponen server alih-alih membiarkannya implisit. OWASP SSRF Prevention Cheat Sheet memperlakukan penolakan di lapisan jaringan terhadap panggilan ke tujuan sembarang sebagai kontrol yang kuat. Postur jaringan tolak-secara-baku di bawah ini merupakan respons jembatan terhadap persyaratan tersebut. National Institute of Standards and Technology (NIST) Special Publication (SP) 800-53 SC-7 menjelaskan prinsip batas tolak-semua-izinkan-melalui-pengecualian yang sama, yang diterapkan jembatan di lapisan transport.
Residensi data dan mitigasi PII
Bagian berjudul “Residensi data dan mitigasi PII”HTML yang diteruskan ke jembatan diproses sepenuhnya di dalam proses dan instans Chrome lokal. Jembatan ini tidak melakukan panggilan jaringan keluar sendiri dan mencegah Chrome melakukan panggilan apa pun (lihat model jaringan di bawah), sehingga konten input tidak meninggalkan host melalui renderer. Personally identifiable information (PII) di dalam input dirender menjadi output Portable Document Format (PDF) yang Anda hasilkan, jadi perlakukan output dengan kontrol residensi yang sama seperti input. Jembatan ini tidak menyimpan input atau output ke disk; persistensi menjadi tanggung jawab pemanggil.
Telemetri aman dan penyaringan log
Bagian berjudul “Telemetri aman dan penyaringan log”ChromeHtmlRenderer dan BrowserPool menerima PHP Standard Recommendation (PSR)-3 LoggerInterface opsional. Jembatan ini hanya mencatat metadata operasional: panjang byte input, lebar dan tinggi target, panjang byte output, tinggi konten terukur, peluncuran peramban beserta path biner yang dikonfigurasi, pemberitahuan mulai ulang dengan jumlah render, dan peristiwa penutupan. Jembatan ini tidak mencatat konten HTML, byte yang dirender, atau teks yang diekstraksi. Hal ini selaras dengan panduan NIST SP 800-92 untuk mencatat peristiwa operasional sembari menjauhkan payload sensitif dari log. Path biner dicatat; perlakukan ini sebagai metadata deployment yang tidak sensitif. Pengujian memverifikasi bentuk pemanggilan log di tests/Unit/Artisan/ChromeHtmlRendererTest.php::renderLogsDebugWithSizeWidthHeightAndPdfSize dan tests/Unit/Artisan/BrowserPoolTest.php::getBrowserLogsInfoOnLaunchWithBinaryPath.
Model isolasi jaringan (pertahanan berlapis)
Bagian berjudul “Model isolasi jaringan (pertahanan berlapis)”Jembatan ini menerapkan dua penghalang independen sehingga jika satu lapisan terlewati, host tidak langsung terekspos:
-
Content-Security-Policy. Setiap render dibungkus oleh
ChromeSecurityPolicy::wrapHtml()ke dalam dokumen yang membawa:default-src 'none'; style-src 'unsafe-inline'; img-src data:;base-uri 'none'; form-action 'none'; frame-ancestors 'none';navigate-to 'none';Direktif Content Security Policy (CSP)
default-src 'none'menolak semua origin sumber daya.img-src data:hanya mengizinkan gambar inline.navigate-to 'none'memblokir navigasi sisi klien.style-src 'unsafe-inline'adalah satu-satunya pelonggaran yang diperlukan agar ChromeprintToPDFdapat menerapkan gaya inline. Hal ini diverifikasi disrc/Artisan/ChromeSecurityPolicy.phpdan ditegaskan olehChromeSecurityPolicyTest::wrapHtmlIncludesNavigationCspDirectives. -
Pemblokiran transport Chrome DevTools Protocol (CDP). Sebelum konten dimuat,
ChromeHtmlRenderermengirimNetwork.enablelaluNetwork.setBlockedURLsdengan pola['*']. Ini memblokir setiap URL subsumber daya di lapisan transport Chrome DevTools Protocol, terlepas dari CSP. Hal ini diverifikasi disrc/Artisan/ChromeHtmlRenderer::blockAllNetworkRequests()dan ditegaskan olehChromeHtmlRendererTest::renderAutoFitsHeightAndBlocksNetworkRequests(yang memeriksa urutan metode CDP yang tepat dan parameter['urls' => ['*']]). Ini adalah pemblokiran di lapisan jaringan yang direkomendasikan panduan OWASP SSRF sebagai kontrol terkuat, dan merupakan penolakan-semua di tingkat transport yang konsisten dengan NIST SP 800-53 SC-7.
Hasilnya: URL <img>, lembar gaya, fon, skrip, atau iframe jarak jauh di dalam input tidak dimuat. Jembatan ini tidak menerapkan daftar izin domain atau filter IP privat karena memang tidak membutuhkannya: jembatan ini tidak mengizinkan pengambilan subsumber daya keluar sama sekali.
Catatan drift: docblock
nextpdf/corepadawriteHtmlChrome()menyatakan Chrome “akan mengambil sumber daya eksternal” dan menyarankan mengonfigurasi kebijakan untuk “memblokir rentang IP privat dan membatasi domain yang diizinkan.” Pernyataan itu menggambarkan model daftar izin yang dapat dikonfigurasi.ChromeSecurityPolicyArtisan yang dikirimkan tidak mengekspos daftar izin; jembatan ini memblokir semua permintaan subsumber daya tanpa syarat. Yang otoritatif adalah kode, bukan docblock core. Drift ini dicatat untuk tim dokumentasi core.
Validasi input (pra-Chrome)
Bagian berjudul “Validasi input (pra-Chrome)”ChromeSecurityPolicy::validate() dijalankan sebelum jembatan menghubungi Chrome dan menolak:
| Pemeriksaan | Batas | Alasan |
|---|---|---|
| Ukuran HTML | > maxHtmlSize (baku 5 MB) | Batas untuk penipisan sumber daya (uncontrolled resource consumption CWE Top 25) |
| Data URI base64 | grup tangkap >= 13_000_000 byte | Batas bom dekompresi |
<meta http-equiv="refresh"> | apa pun (tidak peka huruf besar/kecil, single/double quote) | Memblokir pengalihan sisi klien ke endpoint internal, yang merupakan vektor navigasi SSRF |
Pemblokiran meta-refresh adalah pengerasan SSRF yang eksplisit. Tanpanya, HTML yang dikendalikan penyerang dapat mengalihkan Chrome ke endpoint metadata cloud sebelum printToPDF. Perilaku batas ini ditegaskan dalam ChromeSecurityPolicyTest (validateThrowsOnOversizedHtml, validateRejectsMetaRefreshRedirect, validateRejectsMetaRefreshCaseInsensitive, validateRejectsMetaRefreshWithSingleQuotes, validateRejectsOversizedBase64DataUri, validateRejectsBase64DataUriAtExactThreshold).
Selain itu, ChromeSecurityPolicy::wrapHtml() menghapus </style> dari defaultCss sebelum injeksi untuk mencegah blok gaya keluar ke konteks skrip (ditegaskan oleh ChromeSecurityPolicyTest::wrapHtmlStripsStyleClosingTagsFromDefaultCss).
Batas sandbox Chrome — dinyatakan secara eksplisit
Bagian berjudul “Batas sandbox Chrome — dinyatakan secara eksplisit”Sandbox tingkat sistem operasi milik Chrome merupakan kontrol yang terpisah dari penghalang jaringan di atas, dan jembatan ini tidak menjaminnya.
- Secara baku,
noSandboxbernilaifalse, sehingga Chrome diluncurkan dengan sandbox-nya sendiri aktif. Jembatan ini tidak mengimplementasikan sandbox tersebut; ia mengandalkan sandbox dari biner Chrome, yang bergantung pada dukungan kernel host. - Menyetel
noSandbox: truemeluncurkan Chrome dengan--no-sandbox. Ini menghapus sandbox isolasi-proses Chrome. Opsi ini disediakan untuk kontainer di mana sandbox tidak dapat diinisialisasi. Ini merupakan pengurangan isolasi yang nyata: kompromi renderer tidak lagi ditampung oleh sandbox Chrome. - Penghalang jaringan jembatan (CSP + blokir CDP) tetap berlaku, baik sandbox aktif maupun tidak, tetapi keduanya bukan pengganti isolasi proses. Panduan least-privilege OWASP ASVS berlaku: jalankan Chrome sebagai pengguna non-root, di dalam kontainer yang terbatas, dengan
noSandboxhanya jika tidak terhindarkan, dan perlakukan deployment--no-sandboxsebagai persyaratan kepercayaan yang lebih tinggi terhadap input.
Dokumentasi ini tidak mengklaim bahwa jembatan “aman secara baku” atau “tahan rusak”. Dokumentasi ini juga tidak mengklaim bahwa menonaktifkan sandbox itu aman. Dokumentasi ini menyatakan kontrol yang ada dan batas berhentinya kontrol tersebut. Penyediaan kontainer yang mendukung sandbox dibahas di halaman /integrations/artisan/chrome-renderer-setup/.
Mode kegagalan
Bagian berjudul “Mode kegagalan”Mode kegagalan ini diuraikan berdasarkan src/Artisan/Exception/ dan kode render/transport:
| Kondisi | Muncul sebagai | Sumber |
|---|---|---|
Pustaka chrome-php/chrome tidak ada | ChromeNotAvailableException (dengan perintah pemasangan) | BrowserPool::getBrowser() |
HTML melebihi maxHtmlSize | RuntimeException (“exceeds maximum allowed size”) | ChromeSecurityPolicy::validate() |
| Data URI base64 berukuran berlebih | RuntimeException (“oversized base64 data URI”) | ChromeSecurityPolicy::validate() |
| Meta-refresh terlarang | RuntimeException (“forbidden meta refresh redirect”) | ChromeSecurityPolicy::validate() |
| Peluncuran / batas waktu / crash Chrome | ChromeRenderException (membungkus penyebabnya) | ChromeHtmlRenderer::render() |
| Chrome mengembalikan PDF kosong | ChromeRenderException (“returned empty data”) | ChromeHtmlRenderer::render() |
| Halaman tidak memiliki content stream | PdfParseException | PageImporter::import() |
Jika ChromeRenderException dilempar selama render, exception tersebut dilempar ulang tanpa perubahan. Setiap Throwable lain dibungkus sebagai ChromeRenderException, dengan mempertahankan exception sebelumnya (ditegaskan oleh ChromeHtmlRendererTest::renderRethrowsChromeRenderExceptionWithoutWrapping dan ::renderWrapsUnexpectedThrowablesWithChromeRenderException). Halaman Chrome selalu ditutup di dalam blok finally, bahkan saat gagal.
Batas sumber daya
Bagian berjudul “Batas sumber daya”- Ukuran input:
maxHtmlSize(baku 5 MB) dan batas data URI base64 sebesar 13 MB. - Waktu:
renderTimeoutdetik membatasi pemuatan konten maupun panggilan CDP sinkron. Perintah kontrol CDP menggunakan batas waktu tetap 5 detik. - Proses:
BrowserPoolmemulai ulang Chrome setiap 100 render untuk membatasi pertumbuhan memori dan menutup proses padaclose()/ penghancuran.
Ini adalah batas, bukan kuota. Untuk setiap jalur yang terekspos ke input tidak tepercaya, tetap gunakan batas sumber daya tingkat host (cgroup, ulimit, anggaran permintaan), konsisten dengan panduan konsumsi sumber daya CWE Top 25.
Pengait observabilitas
Bagian berjudul “Pengait observabilitas”Suntikkan logger PSR-3 untuk menangkap awal render (ukuran, lebar, tinggi), render selesai (ukuran output, tinggi konten), peluncuran peramban (path biner), mulai ulang peramban (jumlah render), dan penutupan peramban (jumlah render). Ini adalah satu-satunya peristiwa yang dipancarkan, dan semuanya tidak membawa konten payload. Gunakan peristiwa tersebut untuk service-level objective (SLO) latensi dan peringatan laju mulai ulang.
Konformitas
Bagian berjudul “Konformitas”| Klaim | Referensi | clause_id | reference_id |
|---|---|---|---|
| Permintaan keluar dari komponen server harus dikendalikan | OWASP ASVS 5.0 | § (SSRF/kontrol keluar) | |
| SSRF = server mengambil URL yang diberikan tanpa memvalidasi tujuannya | CWE Top 25 2025 (CWE-918) | cwe_top25_2025#x28.x2.p2 | |
| SSRF (CWE-918) adalah kelemahan CWE Top 25 | CWE Top 25 2025 | cwe_top25_2025#x1.p73 | |
| Konsumsi sumber daya tak terkendali adalah kelemahan CWE Top 25 | CWE Top 25 2025 (CWE-400) | cwe_top25_2025#x19.x2.p2 | |
| Perlindungan batas tolak-secara-baku (izinkan melalui pengecualian) | NIST SP 800-53 Rev 5 SC-7 | SC-7 | |
| Penolakan di lapisan jaringan terhadap panggilan ke tujuan sembarang adalah kontrol SSRF yang kuat | OWASP Cheat Sheet Series (SSRF Prevention §Network layer) | owasp_cheatsheet_series#x132.x2 | |
| Lindungi komponen pengambil-URL terhadap SSRF | OWASP Cheat Sheet Series | § (pencegahan SSRF, perkakas pengambil-URL) | |
| Isolasi renderer untuk konten tidak tepercaya, least privilege | OWASP ASVS 5.0 | § (sandbox / least privilege) | |
| Catat peristiwa operasional; jauhkan payload dari log | NIST SP 800-92 | § (panduan konten log) |
Rujukan diambil melalui mesin kepatuhan NextPDF (manifes korpus 1d05b7c4…d790b6); teks klausa diparafrasekan, tidak pernah dikutip langsung.
Model ancaman
Bagian berjudul “Model ancaman”| Ancaman | Kontrol | Risiko residual |
|---|---|---|
| SSRF melalui subsumber daya jarak jauh | CSP default-src 'none' + CDP setBlockedURLs('*') | Bug pada mesin Chrome yang melewati kedua penghalang (pertahanan berlapis menurunkan risiko, tetapi tidak menghilangkannya) |
| SSRF melalui navigasi meta-refresh | Validasi pra-Chrome menolak tag tersebut | Vektor navigasi baru yang tidak cocok dengan pola tersebut |
| Penipisan sumber daya | Batas ukuran input + batas base64 + batas waktu + mulai ulang setiap 100 render | Tidak ada kuota per host; padukan dengan cgroup/ulimit |
| Kompromi proses renderer | Sandbox Chrome saat aktif | noSandbox: true menghapus kontrol ini sepenuhnya |
| Pelarian gaya / injeksi | Penghapusan </style> di defaultCss; CSP memblokir skrip | Injeksi melalui vektor di masa depan yang tidak dihapus |
Perilaku mode FIPS
Bagian berjudul “Perilaku mode FIPS”Jembatan ini tidak melakukan operasi kriptografis apa pun. Ia menghasilkan byte PDF melalui Chrome dan menyematkannya. Penandatanganan, enkripsi, dan perilaku mode Federal Information Processing Standards (FIPS) menjadi urusan core/Premium dan tidak terpengaruh oleh Artisan.
Lihat juga
Bagian berjudul “Lihat juga”- /integrations/artisan/configuration/
- /integrations/artisan/chrome-renderer-setup/
- /integrations/artisan/troubleshooting/
- /integrations/artisan/production-usage/
- /integrations/artisan/overview/