Lewati ke konten

Keamanan dan operasi

Jembatan ini mengirimkan Hypertext Markup Language (HTML) Anda melewati batas jaringan menuju mesin peramban. Halaman ini mendokumentasikan kontrol yang melindungi batas tersebut, dengan kode sumber sebagai acuan kebenaran. Ketika sebuah kontrol mengutip suatu standar, kutipan itu adalah kutipan yang dideklarasikan dalam docblock kode. Halaman ini menyatakan ulang penegasan kode; halaman ini tidak menyusun ulang rumusan normatif.

Docblock paket ini menyebutkan ancaman yang ditangkal:

  • XSS-ke-PDF — Cross-site scripting (XSS) melalui markup berbahaya yang dieksekusi selama proses render Portable Document Format (PDF).
  • SSRF — Server-side request forgery (SSRF) akibat markup atau Uniform Resource Locator (URL) tujuan yang mengirim permintaan ke alamat internal.
  • Penghabisan sumber daya — Input yang terlalu besar atau bom dekompresi.
  • Rebinding DNS — rebinding Domain Name System (DNS), ketika sebuah hostname lolos validasi lalu dipetakan ke alamat privat saat koneksi dilakukan.
  • Penyadapan TLS on-path — penyadapan Transport Layer Security (TLS) on-path melalui sertifikat yang diganti pada jalur menuju Worker.

Setiap ancaman memiliki kontrol spesifik yang dapat diuji di bawah ini.

Kontrol input (sebelum permintaan meninggalkan PHP)

Bagian berjudul “Kontrol input (sebelum permintaan meninggalkan PHP)”

CloudflareSecurityPolicy::validate() berjalan sebelum permintaan apa pun dibuat:

KontrolPerilakuSumber batas
Batas ukuranMenolak HTML yang lebih besar daripada maxHtmlSizeCloudflareRendererConfig, baku 5000000 bita
Pelindung bom-dekompresi Base64Memperkirakan ukuran hasil dekode dari setiap URI data:…;base64,…; menolak nilai yang mencapai atau melampaui batas atasMAX_DATA_URI_BYTES = 13631488
Larangan meta-refreshMenolak setiap <meta http-equiv="refresh">, tanpa membedakan huruf besar-kecilregex di CloudflareSecurityPolicy

Pelanggaran memunculkan RuntimeException dengan pesan yang menyebutkan nilai yang melanggar beserta batasnya. Larangan meta-refresh ada karena direktif refresh dapat memulai navigasi di dalam halaman yang dirender Worker — vektor SSRF yang berada di dalam konten, bukan di URL.

Kebijakan keamanan HTML dari nextpdf/core (HtmlSecurityPolicyInterface, baku DefaultHtmlSecurityPolicy) berjalan di lapisan penguraian dan melengkapi pemeriksaan lapisan transpor di atas. Ambil kebijakan ini dengan getHtmlSecurityPolicy(). Suntikkan kebijakan kustom melalui konstruktor.

CloudflareSecurityPolicy::validateWorkerUrl():

  1. Menolak URL yang gagal diurai atau tidak memiliki scheme/host (Invalid Worker URL).
  2. Menolak skema apa pun selain HTTPS (Worker URL must use HTTPS).
  3. Untuk host berupa IP literal, menolak rentang privat atau yang dicadangkan dengan FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE milik PHP. Pada praktiknya, hal ini menolak ruang privat RFC 1918, loopback, dan alamat link-local RFC 3927. Pengujian secara eksplisit mencakup penolakan 192.168.x, 127.0.0.1, dan 169.254.x. Keanggotaan rentang ditentukan oleh ekstensi filter PHP; paket ini tidak menyematkan keputusan tersebut ke suatu klausa. RFC 1918 dan RFC 3927 disebutkan di sini secara deskriptif sebagai definisi yang lazim dikenal untuk rentang-rentang tersebut.
  4. Untuk hostname, memetakan semua rekaman A dan AAAA dengan dns_get_record() (bukan gethostbyname(), yang hanya mengembalikan jawaban pertama) dan menolak host jika ada alamat hasil pemetaan yang bersifat privat atau dicadangkan.

Pemetaan seluruh rekaman digunakan dengan sengaja. Docblock kelas mendokumentasikannya sebagai pertahanan terhadap host yang mengembalikan beberapa rekaman, ketika pencarian satu rekaman mungkin memilih alamat publik sementara koneksi berikutnya memilih alamat privat. Hal ini sejalan dengan OWASP SSRF Prevention Cheat Sheet: petakan jawaban A maupun AAAA untuk domain dan terapkan pemeriksaan alamat nonpublik pada seluruh set hasil.

validateWorkerUrl() mengembalikan set IP yang telah diperiksa. Tepat sebelum mengirim permintaan, renderer memanggil assertPinsStillValid(). Panggilan itu memetakan ulang host dan menolak IP yang baru muncul (Worker URL DNS answer changed since validation — possible DNS rebinding attack). Hal ini menutup celah time-of-check / time-of-use antara validasi dan koneksi.

Ketika set IP yang telah diperiksa atau set pin Subject Public Key Info (SPKI) tersedia dan sebuah ResponseFactory PHP Standards Recommendation 17 (PSR-17) disediakan, renderer menggunakan Transport\PinnedCurlTransport alih-alih klien PHP Standards Recommendation 18 (PSR-18) yang disuntikkan. Transpor menegakkan kontrol berikut pada lapisan handle cURL:

  • DNS yang disematkanCURLOPT_RESOLVE mengikat host:port ke set IP yang telah diperiksa, sehingga libcurl tidak melakukan pencarian sendiri saat koneksi. Pengikatan ini membuat pemeriksaan DNS di sisi userland berlaku pada koneksi yang sebenarnya; tanpanya, libcurl bisa memetakan ke alamat yang berbeda.
  • Penyematan kunci publik TLSCURLOPT_PINNEDPUBLICKEY diatur dari set pin gabungan. Hal ini mengikuti RFC 7469 §2.6: koneksi dengan pin diterima ketika set sidik jari SPKI yang disajikan server beririsan dengan set pin yang dikonfigurasi, dan kegagalan validasi pin tidak dapat dipulihkan. String pin dinormalisasi dari bentuk sha256/<base64> ke bentuk sha256//<base64> milik cURL; pin yang cacat memunculkan InvalidSpkiPinException.
  • Verifikasi TLS aktifCURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2.
  • Tanpa pengalihan otomatisCURLOPT_FOLLOWLOCATION => false, CURLOPT_MAXREDIRS => 0. Respons 3xx dimunculkan ke lapisan kebijakan, bukan diikuti oleh libcurl menuju host yang belum diperiksa. Docblock kelas menyatakan bahwa ini disengaja, sehingga pengalihan divalidasi ulang alih-alih diikuti secara diam-diam.
  • Batas waktu tegasCURLOPT_TIMEOUT diatur dari renderTimeout (baku 30 detik).

Kesalahan cURL atau body yang bukan string memunculkan CloudflareRenderException beserta nomor dan pesan kesalahan cURL.

Konfigurasi memuat pinnedPublicKeys dan backupPublicKeys secara terpisah. RFC 7469 §2.5 menjelaskan pin cadangan sebagai sidik jari untuk pasangan kunci sekunder yang belum di-deploy dan disimpan secara offline, serta memperlakukannya sebagai jalur pemulihan utama untuk kegagalan validasi pin yang tidak disengaja. Simpan setidaknya satu pin cadangan agar rotasi sertifikat tidak membuat endpoint tidak dapat diakses. Field terpisah memungkinkan Anda memvalidasi rotasi secara independen. Secara operasional:

  • Sematkan SPKI dari sertifikat leaf atau dari sertifikat antara yang rotasinya Anda kendalikan.
  • Selalu konfigurasikan pin cadangan untuk sertifikat berikutnya sebelum melakukan rotasi.
  • Set pin kosong menonaktifkan penyematan; gunakan itu hanya dengan rantai sertifikat yang stabil dan diketahui. Penyematan bersifat opt-in melalui konfigurasi.
  • Permintaan Worker membawa Authorization: Bearer <apiToken>. apiToken ber-#[SensitiveParameter], sehingga stack trace menyensornya. Probe keterjangkauan mengirim header bearer yang sama pada Hypertext Transfer Protocol (HTTP) HEAD.
  • Kunci akses Cloudflare R2 (accessKeyId, secretAccessKey) ber-#[SensitiveParameter] dan hanya digunakan untuk menurunkan kunci penandatanganan Amazon Web Services (AWS) Signature V4.
  • ApiKeyValidator membandingkan kunci dengan hash_equals() (aman terhadap timing) dan mendukung penyimpanan kunci yang sudah di-hash Secure Hash Algorithm 256 (SHA-256) melalui validateHashed().
  • Objek konfigurasi bersifat final readonly — rahasia yang sudah disetel sekali tidak dapat diubah.
  • Ambil rahasia dari variabel lingkungan atau pengelola rahasia. Jangan pernah meng-commit rahasia tersebut. Paket ini mengikuti baseline keamanan NextPDF yang lebih luas: PHPStan Level 10, declare(strict_types=1) pada setiap berkas, tanpa eval()/exec(), GitHub Actions disematkan ke SHA.
  • Paket ini tidak menyatakan batas platform Cloudflare apa pun (waktu CPU Worker, memori, batas atas body permintaan, atau jumlah subpermintaan). Satu-satunya batas ukuran dan waktu yang dinyatakan dokumentasi ini adalah batas yang ditegakkan sendiri oleh paket, sebagaimana tercantum di atas dan di /integrations/cloudflare/configuration/. Untuk batas platform, rujuk dokumentasi resmi Cloudflare dan implementasi Worker Anda sendiri.
  • Paket ini tidak menandatangani PDF dan tidak membuat klaim kesesuaian tanda tangan. Ketika tanda tangan diperlukan, render di sini, lalu tandatangani dengan mesin penandatanganan Anda. NextPDF Pro hanya menyediakan penandatanganan PDF Advanced Electronic Signatures (PAdES) B-B; profil long-term-validation merupakan kapabilitas Enterprise dan berada di luar cakupan jembatan ini.
  • Paket ini tidak menyertifikasi, menjamin, atau menjadikan pipeline “tamper-proof”. Paket ini hanya mengimplementasikan kontrol spesifik yang dapat diverifikasi dari kode sumber seperti yang dijelaskan pada halaman ini.
GejalaPemeriksaan pertama
Worker URL must use HTTPSPeriksa skema workerUrl yang dikonfigurasi.
private or reserved IPPeriksa rekaman DNS dari hostname Worker; cari rekaman yang memetakan ke ruang RFC 1918 / loopback / RFC 3927.
DNS answer changed since validationKetidakstabilan DNS atau upaya rebinding; petakan ulang dan periksa seluruh set rekaman.
cURL transport errorJalur jaringan, rantai TLS, dan — jika pin disetel — apakah SPKI dari sertifikat yang disajikan masih ada dalam set pin.
Render gagal tepat setelah rotasi sertifikatSet pin tanpa pin cadangan yang cocok. Tambahkan SPKI baru sebagai cadangan sebelum melakukan rotasi.
is not installed / no LocalRendererFactoryInterfaceFallback diaktifkan tetapi tidak ada factory yang terhubung, atau nextpdf/artisan tidak ada.
Penolakan rate limit tidak konsisten antarnodeLimiter in-memory bersifat per-proses; tempatkan penyimpanan bersama di depannya.

Laporkan kerentanan melalui GitHub Security Advisories atau kontak keamanan di SECURITY.md repositori. Jangan melaporkan isu keamanan sebagai GitHub issue publik.

  • /integrations/cloudflare/overview/ — mengapa paket ini dirancang seputar batas tersebut.
  • /integrations/cloudflare/configuration/ — field untuk set pin dan batas.
  • /integrations/cloudflare/troubleshooting/ — pemetaan lengkap kegagalan ke eksepsi.