Subresource Integrity untuk Script Eksternal - Biarkan Browser Memverifikasi Byte
Satu tag <script> eksternal dapat terlihat hampir sepele. Namun, tag itu meminta browser setiap pengunjung mengunduh code dari server lain dan menjalankannya di dalam halaman. HTTPS melindungi perjalanan menuju server tersebut, tetapi apa yang memeriksa bahwa file yang dikembalikan benar-benar versi yang diharapkan pemilik situs?
Subresource Integrity (SRI) memberi browser cryptographic digest yang diharapkan untuk sebuah resource. Jika byte yang diunduh tidak cocok, browser menolak menggunakannya. Ini adalah kontrol yang sempit, bukan pertahanan supply chain yang lengkap, tetapi justru kesempitan itu berguna: SRI menjawab satu pertanyaan konkret sebelum script eksternal dijalankan atau stylesheet diterapkan.
Kepercayaan yang tersembunyi di dalam resource eksternal
Bayangkan sebuah halaman menyertakan library dari content delivery network:
<script src="https://cdn.example.com/library-4.2.1.min.js"></script>
Halaman itu mendelegasikan lebih dari sekadar pengiriman file. JavaScript yang dimuat dengan cara ini berjalan dalam konteks halaman. OWASP Third Party JavaScript Management Cheat Sheet menyoroti hilangnya kendali yang menyertainya: code pihak ketiga dapat berubah di luar proses rilis situs, menjalankan code pada client, dan memperoleh akses ke informasi yang tersedia di halaman.
TLS tetap penting. Ia membantu browser berkomunikasi dengan server yang dituju tanpa perantara dengan mudah menulis ulang response. Namun, W3C SRI Recommendation membuat pembedaan penting: secure transport mengautentikasi koneksi, sedangkan SRI mengunci konten yang diharapkan. Jika CDN, proses deployment-nya, atau file di balik URL yang mutable berubah, koneksi HTTPS yang valid tetap dapat mengirim byte yang tidak pernah ditinjau oleh pengelola website.
Apa yang sebenarnya diverifikasi browser
Nilai SRI memuat nama algoritma hash dan digest dengan encoding base64. W3C Recommendation yang stabil menetapkan SHA-256, SHA-384, dan SHA-512 untuk tujuan ini. Nilai SHA-384 yang umum memiliki bentuk seperti berikut:
sha384-aZEZqsD0hQTrQxOOiN+3hK9zrIM0coHjnIZM4RkuhmT3K0qz+sJn2b0NZNhsunyB
Digest bukan encryption, password, atau bukti siapa yang menulis file tersebut. Ia adalah hasil ringkas yang dihitung dari byte yang persis sama. Halaman mendeklarasikan hasil yang diharapkan dalam atribut integrity. Browser mengunduh resource, menghitung digest-nya, lalu membandingkan kedua nilai sebelum menjalankan script atau menerapkan stylesheet. Jika berbeda, browser memperlakukan pemuatan itu sebagai network error.
Kegagalan tersebut memang disengaja. SRI mengubah perubahan konten yang tidak terlihat menjadi resource yang diblokir. Integritas meningkat dengan mengorbankan availability: script yang berubah dapat menghentikan sebuah fitur, sedangkan stylesheet yang berubah dapat membuat halaman kehilangan gaya. Kontrol ini hanya bermanfaat jika situs juga memiliki proses pembaruan dan penanganan kegagalan yang disengaja.
Buat digest dari byte yang akan di-deploy
Anggap library-4.2.1.min.js adalah file yang telah ditinjau. Panduan SRI MDN mendokumentasikan pipeline OpenSSL untuk membuat digest SHA-384:
openssl dgst -sha384 -binary library-4.2.1.min.js | openssl base64 -A
Untuk file uji lokal yang berisi console.log("SRI example"); diikuti newline, command tersebut telah diverifikasi menghasilkan:
aZEZqsD0hQTrQxOOiN+3hK9zrIM0coHjnIZM4RkuhmT3K0qz+sJn2b0NZNhsunyB
Tambahkan awalan sha384- pada hasilnya. Yang lebih penting, hash-lah artifact yang sama dengan yang akan diterima pengunjung. Melakukan hash pada source file lalu meminta build tool, CDN, atau optimizing proxy untuk melakukan minify atau transformasi lain akan menghasilkan byte berbeda dan karena itu terjadi mismatch. Perubahan line ending pun merupakan perubahan byte.
Download jarak jauh juga dapat di-hash, tetapi perlu kehati-hatian: membuat digest dari apa pun yang dikembalikan sebuah URL hari ini tidak membuktikan bahwa file tersebut dapat dipercaya. Tinjau versinya dan dapatkan melalui jalur rilis tepercaya terlebih dahulu. SRI dapat mempertahankan keputusan itu, tetapi tidak dapat mengambil keputusan untukmu.
Tambahkan integrity metadata pada script dan style
Untuk script yang di-host pada origin lain, markup-nya dapat terlihat seperti ini:
<script
src="https://cdn.example.com/library-4.2.1.min.js"
integrity="sha384-aZEZqsD0hQTrQxOOiN+3hK9zrIM0coHjnIZM4RkuhmT3K0qz+sJn2b0NZNhsunyB"
crossorigin="anonymous"></script>
Mekanisme yang sama melindungi stylesheet eksternal:
<link
rel="stylesheet"
href="https://cdn.example.com/theme-4.2.1.min.css"
integrity="sha384-REPLACE_WITH_THE_STYLESHEET_DIGEST"
crossorigin="anonymous">
Placeholder tersebut memang disengaja: stylesheet membutuhkan digest yang dihitung dari byte-nya sendiri. Menggunakan ulang digest script adalah tindakan yang keliru.
Mengapa crossorigin="anonymous" penting
Untuk resource cross-origin, validasi SRI membutuhkan response yang memenuhi syarat CORS. Menambahkan crossorigin="anonymous" membuat elemen memakai mode CORS tanpa mengirim credential lintas origin. Server asset juga harus mengembalikan header Access-Control-Allow-Origin yang sesuai. Jika CDN tidak mengizinkan CORS, menambahkan digest saja tidak akan membuat resource berhasil dimuat.
Hal ini perlu diuji dari origin halaman yang sebenarnya, bukan hanya dengan membuka URL asset di sebuah tab. Direct request yang menghasilkan HTTP 200 tidak membuktikan bahwa cross-origin request dan pemeriksaan integritas oleh browser akan berhasil.
Workflow rollout dan pembaruan yang hati-hati
SRI paling cocok saat URL resource mengidentifikasi versi immutable. URL yang berakhir dengan 4.2.1 menyampaikan kontrak yang lebih baik daripada latest.js, tetapi nama saja bukanlah bukti; host harus benar-benar menjaga byte-nya tetap sama.
Workflow untuk situs kecil dapat tetap sederhana:
- Inventarisasi script dan style yang dimuat secara eksternal, termasuk asset yang disisipkan oleh template, plugin, consent tool, dan tag manager.
- Hapus dependency yang memberikan manfaat terlalu kecil dibandingkan kepercayaan yang dibutuhkannya.
- Pilih versi tetap serta tinjau sumber rilis dan tujuannya.
- Dapatkan artifact yang persis sama, hitung digest-nya, lalu tambahkan nilai
integrityyang cocok. - Konfirmasi response CORS dari host asset dan uji halaman sebenarnya di browser.
- Ubah sementara digest pada salinan uji dan pastikan browser memblokirnya serta melaporkan integrity error di developer tools.
- Dokumentasikan cara memperbarui versi dan digest secara bersamaan, lalu pantau halaman penting setelah rilis.
Uji bad-digest yang disengaja sebaiknya dilakukan pada salinan non-production. Pengujian itu memeriksa jalur kegagalan tanpa mengklaim bahwa setiap browser, proxy, atau lingkungan deployment berperilaku identik di luar persyaratan standar.
Apa yang tidak diselesaikan SRI
Nama “integrity” dapat terdengar lebih luas daripada mekanismenya. Beberapa batas berikut penting:
- SRI tidak membuat code menjadi aman. File yang rentan atau mengganggu privasi dapat cocok sempurna dengan digest-nya. SRI membuktikan kesesuaian dengan byte yang diharapkan, bukan perilaku yang baik.
- SRI tidak menggantikan pembaruan. Mengunci library lama juga mengunci kekurangannya. Monitoring dependency dan proses pembaruan terkendali tetap diperlukan.
- SRI tidak menggantikan HTTPS. Pada halaman HTTP, penyerang yang dapat mengubah dokumen juga dapat menghapus atau mengganti integrity metadata-nya.
- SRI tidak menjamin availability. Pembaruan vendor, transformasi, kesalahan CORS, atau CDN yang tidak tersedia dapat membuat resource terlindungi tetap diblokir.
- SRI tidak membatasi setiap request berikutnya. Loader kecil yang byte-nya cocok masih dapat mengambil code atau data dinamis. Analisis kepercayaan harus mencakup tindakan pinned script setelah mulai berjalan.
- SRI bukan digital signature. Digest tidak membawa identitas publisher yang independen. Siapa pun yang mampu mengubah HTML dan resource dapat mengganti kedua nilai tersebut.
Content Security Policy melengkapi SRI, bukan menggandakannya. CSP dapat membatasi origin atau bentuk script yang diizinkan halaman; SRI memeriksa apakah resource tertentu yang diambil cocok dengan byte yang diharapkan. Self-hosting dapat mengurangi ketergantungan langsung pada runtime host pihak ketiga, tetapi memindahkan tanggung jawab delivery, patching, dan monitoring kepada pemilik situs. Tidak satu pun pilihan ini menghapus kebutuhan untuk memahami dependency tersebut.
Kapan SRI cocok digunakan?
SRI sangat cocok untuk JavaScript atau CSS eksternal berversi yang byte persisnya perlu tetap stabil hingga pembaruan terencana. SRI kurang cocok untuk URL yang sengaja menyajikan konten berubah-ubah, kecuali penyedianya menawarkan versi immutable atau situs dapat mendesain ulang integrasinya. Untuk tag manager dinamis, hanya mengunci loader awal dapat memberikan perlindungan lebih sedikit daripada yang tersirat oleh markup.
Karena itu, pertanyaan praktisnya bukan “Apakah setiap file eksternal harus mendapat hash?” Pertanyaannya adalah “Bisakah dependency ini dijadikan artifact immutable yang telah ditinjau dengan proses pembaruan yang mampu kita operasikan?” Jika bisa, SRI memberi browser tugas enforcement yang kecil tetapi bermakna. Jika tidak, mismatch tersebut mengungkap keputusan arsitektur yang lebih besar: menerima kendali pihak ketiga yang dinamis, mengisolasinya dengan lebih hati-hati, melakukan self-host pada artifact yang disetujui, mengganti dependency, atau menghapusnya.
Kesimpulan
Subresource Integrity mengubah janji implisit menjadi perbandingan yang ditegakkan browser: script atau stylesheet ini harus sama dengan byte yang diharapkan. Deployment yang benar membutuhkan artifact yang persis sama, digest yang sesuai, CORS untuk resource cross-origin, pengujian browser, serta proses yang memperbarui URL dan hash secara bersamaan.
Batasnya sama penting dengan sintaksnya. SRI tidak mengesahkan authorship, menemukan kerentanan, menjaga availability, atau menjinakkan loader dinamis sembarang. Namun, jika digunakan saat byte memang seharusnya stabil, SRI mempersempit keputusan kepercayaan kepada pihak ketiga menjadi sesuatu yang benar-benar dapat diperiksa browser.
