Mengamankan Situs Web Anda Dengan Integritas Sub-Sumber Daya

Saat Anda memuat file dari server eksternal, Anda percaya bahwa konten yang Anda minta adalah seperti yang Anda harapkan. Karena Anda tidak mengelola server sendiri, Anda mengandalkan keamanan pihak ketiga lain dan meningkatkan permukaan serangan. Mempercayai pihak ketiga tidak secara inheren buruk, tetapi tentu saja harus dipertimbangkan dalam konteks keamanan situs web Anda.

Contoh dunia nyata

Ini bukan bahaya teoretis murni. Mengabaikan potensi masalah keamanan dapat dan telah mengakibatkan konsekuensi serius. Pada 4 Juni 2019, Malwarebytes mengumumkan penemuan mereka tentang skimmer jahat di situs web NBA.com. Karena ember Amazon S3 yang disusupi, penyerang dapat mengubah pustaka JavaScript untuk mencuri informasi kartu kredit dari pelanggan.

Bukan hanya JavaScript yang perlu dikhawatirkan. CSS adalah sumber daya lain yang mampu melakukan tindakan berbahaya seperti mencuri kata sandi, dan yang diperlukan hanyalah satu server pihak ketiga yang dikompromikan agar bencana terjadi. Tetapi mereka dapat memberikan layanan yang sangat berharga yang tidak dapat kita lewatkan begitu saja, seperti CDN yang mengurangi total penggunaan bandwidth situs dan menyajikan file ke pengguna akhir lebih cepat karena caching berbasis lokasi. Jadi sudah pasti bahwa terkadang kita perlu mengandalkan host yang tidak dapat kita kendalikan, tetapi kita juga perlu memastikan bahwa konten yang kita terima darinya aman. Apa yang bisa kita lakukan?

Solusi: Integritas Subsumberdaya (SRI)

SRI adalah kebijakan keamanan yang mencegah pemuatan sumber daya yang tidak sesuai dengan hash yang diharapkan. Dengan melakukan ini, jika penyerang mendapatkan akses ke file dan memodifikasi isinya agar mengandung kode berbahaya, itu tidak akan cocok dengan hash yang kami harapkan dan tidak dieksekusi sama sekali.

Bukankah HTTPS sudah melakukannya?

HTTPS sangat bagus untuk keamanan dan harus dimiliki untuk situs web apa pun, dan meskipun mencegah masalah serupa (dan banyak lagi), HTTPS hanya melindungi dari gangguan data dalam perjalanan. Jika file dirusak pada host itu sendiri, file berbahaya akan tetap dikirim melalui HTTPS, tidak melakukan apa pun untuk mencegah serangan.

Bagaimana cara kerja hashing?

Fungsi hashing mengambil data dengan ukuran berapa pun sebagai input dan mengembalikan data dengan ukuran tetap sebagai output. Fungsi hashing idealnya memiliki distribusi yang seragam. Ini berarti bahwa untuk setiap input, x , probabilitas bahwa output, y , akan menjadi nilai spesifik apa pun yang mungkin, sama dengan probabilitasnya menjadi nilai lain dalam rentang output.

Berikut metaforanya:

Misalkan Anda memiliki dadu bersisi 6 dan daftar nama. Nama, dalam hal ini, akan menjadi "input" fungsi hash dan nomor yang digulung akan menjadi "output" fungsi. Untuk setiap nama dalam daftar, Anda akan melempar dadu dan melacak nama yang sesuai dengan setiap nomor nomor, dengan menulis nomor di sebelah nama. Jika sebuah nama digunakan sebagai input lebih dari sekali, output yang sesuai akan selalu seperti yang pertama kali. Untuk nama depan, Alice, kamu lempar 4. Untuk selanjutnya, John, kamu lempar 6. Kemudian untuk Bob, Mary, William, Susan, dan Joseph, kamu mendapatkan masing-masing 2, 2, 5, 1, dan 1. Jika Anda menggunakan "John" sebagai input lagi, output akan menjadi 6. Metafora ini menjelaskan bagaimana fungsi hash bekerja pada dasarnya.

Nama (masukan) Nomor digulung (keluaran)
Alice 4
John 6
Bob 2
Maria 2
William 5
Susan 1
Joseph 1

Anda mungkin telah memperhatikan bahwa, misalnya, Bob dan Mary memiliki keluaran yang sama. Untuk fungsi hashing, ini disebut "tabrakan." Untuk skenario contoh kami, itu pasti terjadi. Karena kami memiliki tujuh nama sebagai input dan hanya enam kemungkinan keluaran, kami dijamin setidaknya satu tabrakan.

Perbedaan penting antara contoh ini dan fungsi hash dalam praktiknya adalah bahwa fungsi hash praktis biasanya bersifat deterministik, artinya mereka tidak menggunakan keacakan seperti yang dilakukan contoh kita. Sebaliknya, ini dapat diprediksi memetakan input ke output sehingga setiap input memiliki kemungkinan yang sama untuk dipetakan ke output tertentu.

SRI menggunakan keluarga fungsi hashing yang disebut algoritma hash aman (SHA). Ini adalah keluarga fungsi hash kriptografi yang mencakup varian 128, 256, 384, dan 512-bit. Fungsi hash kriptografi adalah jenis fungsi hash yang lebih spesifik dengan properti yang secara efektif tidak mungkin dibalik untuk menemukan input asli (tanpa sudah memiliki input yang sesuai atau brute-forcing), tahan benturan, dan dirancang sedemikian rupa untuk perubahan kecil dalam input mengubah seluruh output. SRI mendukung varian 256, 384, dan 512-bit dari keluarga SHA.

Berikut ini contoh dengan SHA-256:

Sebagai contoh. output untuk hello adalah:

 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

Dan output untuk hell0 (dengan nol, bukan O) adalah:

 bdeddd433637173928fe7202b663157c9e1881c3e4da1d45e8fff8fb944a4868

Anda akan melihat bahwa perubahan sekecil apa pun pada input akan menghasilkan output yang sama sekali berbeda. Ini adalah salah satu properti dari hash kriptografi yang disebutkan sebelumnya.

Format yang paling sering Anda lihat untuk hash adalah heksadesimal, yang terdiri dari semua angka desimal (0-9) dan huruf A sampai F. Salah satu manfaat format ini adalah setiap dua karakter mewakili satu byte, dan kemerataan dapat berguna untuk tujuan seperti pemformatan warna, di mana satu byte mewakili setiap warna. Ini berarti warna tanpa saluran alfa dapat direpresentasikan hanya dengan enam karakter (misalnya, merah = ff0000 )

Efisiensi ruang ini juga menjadi alasan kami menggunakan hashing daripada membandingkan keseluruhan file dengan data yang kami harapkan setiap saat. Sementara 256 bit tidak dapat mewakili semua data dalam file yang lebih besar dari 256 bit tanpa kompresi, ketahanan benturan SHA-256 (dan 384, 512) memastikan bahwa hampir tidak mungkin menemukan dua hash untuk input berbeda yang cocok. Dan untuk SHA-1, tidak lagi aman, karena telah ditemukan tabrakan .

Menariknya, daya tarik kekompakan kemungkinan menjadi salah satu alasan hash SRI tidak menggunakan format heksadesimal, dan malah menggunakan base64. Ini mungkin tampak seperti keputusan yang aneh pada awalnya, tetapi ketika kami mempertimbangkan fakta bahwa hash ini akan dimasukkan dalam kode dan bahwa base64 mampu menyampaikan jumlah data yang sama dengan heksadesimal sementara 33% lebih pendek, masuk akal . Satu karakter base64 dapat berada di 64 status berbeda, yaitu data senilai 6 bit, sedangkan hex hanya dapat mewakili 16 status, atau data senilai 4 bit. Jadi jika, misalnya, kita ingin merepresentasikan 32 byte data (256 bit), kita membutuhkan 64 karakter dalam hex, tetapi hanya 44 karakter di base64. Saat kami menggunakan hash yang lebih panjang, seperti sha384/512, base64 menghemat banyak ruang.

Mengapa hashing berfungsi untuk SRI?

Jadi mari kita bayangkan ada file JavaScript yang dihosting di server pihak ketiga yang kami sertakan di halaman web kami dan kami mengaktifkan integritas subsumber daya untuk itu. Sekarang, jika penyerang memodifikasi data file dengan kode berbahaya, hashnya tidak akan lagi cocok dengan hash yang diharapkan dan file tidak akan dieksekusi. Ingatlah bahwa setiap perubahan kecil dalam file benar-benar mengubah hash SHA yang sesuai, dan bentrokan hash dengan SHA-256 dan yang lebih tinggi, pada saat penulisan ini, hampir tidak mungkin.

Hash SRI pertama kami

Jadi, ada beberapa metode yang dapat Anda gunakan untuk menghitung hash SRI dari sebuah file. Salah satu cara (dan mungkin yang paling sederhana) adalah dengan menggunakan srihash.org , tetapi jika Anda lebih suka cara yang lebih terprogram, Anda dapat menggunakan:

 sha384sum [filename here] | head -c 96 | xxd -r -p | base64
  • sha384sum Menghitung hash SHA-384 dari sebuah file
  • head -c 96 Memangkas semua kecuali 96 karakter pertama dari string yang disalurkan ke dalamnya
    • -c 96 Menunjukkan untuk memangkas semua kecuali 96 karakter pertama. Kami menggunakan 96 , karena ini adalah panjang karakter hash SHA-384 dalam format heksadesimal
  • xxd -r -p Mengambil input hex yang disalurkan ke dalamnya dan mengubahnya menjadi biner
    • -r Memberitahu xxd untuk menerima hex dan mengubahnya menjadi biner
    • -p Menghapus pemformatan output tambahan
  • base64 xxd output biner dari xxd ke base64

Jika Anda memutuskan untuk menggunakan metode ini, periksa tabel di bawah ini untuk melihat panjang setiap hash SHA.

Algoritma hash bit Byte Karakter Hex
SHA-256 256 32 64
SHA-384 384 48 96
SHA-512 512 64 128

Untuk perintah head -c [x] , x akan menjadi jumlah karakter hex untuk algoritma yang sesuai.

MDN juga menyebutkan perintah untuk menghitung hash SRI:

 shasum -b -a 384 FILENAME.js | awk '{ print $1 }' | xxd -r -p | base64

awk '{print $1}' Menemukan bagian pertama dari string (dipisahkan oleh tab atau spasi) dan meneruskannya ke xxd . $1 mewakili segmen pertama dari string yang dilewatkan ke dalamnya.

Dan jika Anda menjalankan Windows:

 @echo off set bits=384 openssl dgst -sha%bits% -binary %1% | openssl base64 -A > tmp set /pa= < tmp del tmp echo sha%bits%-%a% pause
  • @echo off mencegah perintah yang sedang berjalan ditampilkan. Ini sangat membantu untuk memastikan terminal tidak menjadi berantakan.
  • set bits=384 menyetel variabel yang disebut bits ke 384. Ini akan digunakan nanti dalam skrip.
  • openssl dgst -sha%bits% -binary %1% | openssl base64 -A > tmp lebih kompleks, jadi mari kita bagi menjadi beberapa bagian.
    • openssl dgst menghitung intisari dari file input.
    • -sha%bits% menggunakan variabel, bits , dan menggabungkannya dengan string lainnya menjadi salah satu nilai flag yang mungkin, sha256 , sha384 , atau sha512 .
    • -binary mengeluarkan hash sebagai data biner alih-alih format string, seperti heksadesimal.
    • %1% adalah argumen pertama yang diteruskan ke skrip saat dijalankan.
    • Bagian pertama dari perintah hash file yang disediakan sebagai argumen untuk skrip.
    • | openssl base64 -A > tmp mengubah output biner yang melaluinya menjadi base64 dan menulisnya ke file bernama tmp . -A mengeluarkan base64 ke dalam satu baris.
    • set /pa= <tmp menyimpan isi file, tmp , dalam sebuah variabel, a .
    • del tmp menghapus file tmp
    • echo sha%bits%-%a% akan mencetak tipe tipe hash SHA, bersama dengan base64 dari file input.
    • pause Mencegah terminal menutup.

SRI beraksi

Sekarang setelah kita memahami cara kerja hashing dan SRI, mari kita coba contoh konkret. Kami akan membuat dua file:

 // file1.js alert('Hello, world!');

dan:

 // file2.js alert('Hi, world!');

Kemudian kita akan menghitung hash SHA-384 SRI untuk keduanya:

Nama file SHA-384 hash (base64)
file1.js 3frxDlOvLa6GGEUwMh9AowcepHRx/rwFT9VW9yL1wv/OcerR39FEfAUHZRrqaOy2
file2.js htr1LmWx3PQJIPw5bM9kZKq/FL0jMBuJDxhwdsMHULKybAG5dGURvJIXR9bh5xJ9

Kemudian, mari kita buat file bernama index.html :

 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./file1.js" integrity="sha384-3frxDlOvLa6GGEUwMh9AowcepHRx/rwFT9VW9yL1wv/OcerR39FEfAUHZRrqaOy2" crossorigin="anonymous"></script> <script type="text/javascript" src="./file2.js" integrity="sha384-htr1LmWx3PQJIPw5bM9kZKq/FL0jMBuJDxhwdsMHULKybAG5dGURvJIXR9bh5xJ9" crossorigin="anonymous"></script> </head> </html>

Tempatkan semua file ini di folder yang sama dan mulai server di dalam folder itu (misalnya, jalankan npx http-server di dalam folder yang berisi file dan kemudian buka salah satu alamat yang disediakan oleh http-server atau server pilihan Anda, seperti 127.0.0.1:8080 ). Anda harus mendapatkan dua kotak dialog peringatan. Yang pertama harus mengatakan "Halo, dunia!" dan yang kedua, "Hai, dunia!"

Jika Anda mengubah konten skrip, Anda akan melihat bahwa skrip tersebut tidak lagi dijalankan. Ini adalah integritas subsumber daya yang berlaku. Browser memperhatikan bahwa hash dari file yang diminta tidak sesuai dengan hash yang diharapkan dan menolak untuk menjalankannya.

Kami juga dapat menyertakan beberapa hash untuk sumber daya dan hash terkuat akan dipilih, seperti:

 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./file1.js" integrity="sha384-3frxDlOvLa6GGEUwMh9AowcepHRx/rwFT9VW9yL1wv/OcerR39FEfAUHZRrqaOy2 sha512-cJpKabWnJLEvkNDvnvX+QcR4ucmGlZjCdkAG4b9n+M16Hd/3MWIhFhJ70RNo7cbzSBcLm1MIMItw 9qks2AU+Tg==" crossorigin="anonymous"></script> <script type="text/javascript" src="./file2.js" integrity="sha384-htr1LmWx3PQJIPw5bM9kZKq/FL0jMBuJDxhwdsMHULKybAG5dGURvJIXR9bh5xJ9 sha512-+4U2wdug3VfnGpLL9xju90A+kVEaK2bxCxnyZnd2PYskyl/BTpHnao1FrMONThoWxLmguExF7vNV WR3BRSzb4g==" crossorigin="anonymous"></script> </head> </html>

Browser akan memilih hash yang dianggap paling kuat dan memeriksa hash file tersebut.

Mengapa ada atribut "crossorigin"?

crossorigin memberi tahu browser kapan harus mengirim kredensial pengguna dengan permintaan sumber daya. Ada dua opsi untuk dipilih:

Nilai ( crossorigin= ) Deskripsi
anonymous Permintaan akan memiliki mode kredensial yang disetel ke same-origin dan modenya disetel ke cors.
use-credentials Permintaan akan memiliki mode kredensial yang disetel untuk include dan modenya disetel ke cors .

Minta mode kredensial yang disebutkan

Mode kredensial Deskripsi
same-origin Kredensial akan dikirim dengan permintaan yang dikirim ke domain asal yang sama dan kredensial yang dikirim dari domain asal yang sama akan digunakan.
include Kredensial juga akan dikirim ke domain lintas asal dan kredensial yang dikirim dari domain lintas asal akan digunakan.

Mode permintaan disebutkan

Modus permintaan Deskripsi
cors Permintaan akan menjadi permintaan CORS, yang akan mengharuskan server untuk memiliki kebijakan CORS yang ditentukan. Jika tidak, permintaan akan menimbulkan kesalahan.

Mengapa atribut "crossorigin" diperlukan dengan integritas subsumber daya?

Secara default, skrip dan stylesheet dapat dimuat lintas sumber, dan karena integritas subsumber daya mencegah pemuatan file jika hash sumber daya yang dimuat tidak sesuai dengan hash yang diharapkan, penyerang dapat memuat sumber daya lintas sumber secara massal dan menguji jika pemuatan gagal dengan hash tertentu, sehingga menyimpulkan informasi tentang pengguna yang tidak dapat mereka lakukan.

Saat Anda menyertakan crossorigin , domain cross-origin harus memilih untuk mengizinkan permintaan dari asal permintaan dikirim agar permintaan berhasil. Ini mencegah serangan lintas-asal dengan integritas subsumber daya.

Menggunakan integritas subsumber daya dengan webpack

Mungkin terdengar seperti banyak pekerjaan untuk menghitung ulang hash SRI dari setiap file setiap kali mereka diperbarui, tetapi untungnya, ada cara untuk mengotomatiskannya. Mari kita lihat contoh bersama. Anda memerlukan beberapa hal sebelum memulai.

Node.js dan npm

Node.js adalah runtime JavaScript yang, bersama dengan npm (pengelola paketnya), akan memungkinkan kita menggunakan webpack. Untuk menginstalnya, kunjungi situs web Node.js dan pilih unduhan yang sesuai dengan sistem operasi Anda.

Menyiapkan proyek

Buat folder dan beri nama apa saja dengan mkdir [name of folder] . Kemudian ketik cd [name of folder] untuk menavigasi ke dalamnya. Sekarang kita perlu mengatur direktori sebagai proyek Node, jadi ketik npm init . Ini akan menanyakan beberapa pertanyaan, tetapi Anda dapat menekan Enter untuk melewatinya karena tidak relevan dengan contoh kita.

paket web

webpack adalah pustaka yang memungkinkan Anda menggabungkan file secara otomatis menjadi satu atau lebih bundel. Dengan webpack, kita tidak perlu lagi memperbarui hash secara manual. Sebagai gantinya, webpack akan menyuntikkan sumber daya ke dalam HTML dengan crossorigin atribut integrity dan crossorigin.

Menginstal paket web

Anda harus menginstal webpack dan webpack-cli:

 npm i --save-dev webpack webpack-cli

Perbedaan antara keduanya adalah webpack berisi fungsionalitas inti sedangkan webpack-cli untuk antarmuka baris perintah.

Kami akan mengedit package.json kami untuk menambahkan scripts seperti:

 { //... rest of package.json ..., "scripts": { "dev": "webpack --mode=development" } //... rest of package.json ..., }

Ini memungkinkan kami untuk menjalankan npm run dev dan membangun bundel kami.

Menyiapkan konfigurasi webpack

Selanjutnya, mari kita atur konfigurasi webpack. Ini diperlukan untuk memberi tahu webpack file apa yang perlu ditangani dan bagaimana caranya.

Pertama, kita perlu menginstal dua paket, html-webpack-plugin , dan webpack-subresource-integrity :

 npm i --save-dev html-webpack-plugin webpack-subresource-integrity style-loader css-loader
Nama paket Deskripsi
html-webpack-plugin Membuat file HTML tempat sumber daya dapat disuntikkan
webpack-subresource-integrity Menghitung dan menyisipkan informasi integritas subsumber daya ke dalam sumber daya seperti <script> dan <link rel=…>
gaya-loader Menerapkan gaya CSS yang kita impor
css-loader Memungkinkan kami untuk import file css ke dalam JavaScript kami

Menyiapkan konfigurasi:

 const path = require('path'), HTMLWebpackPlugin = require('html-webpack-plugin'), SriPlugin = require('webpack-subresource-integrity'); module.exports = { output: { // The output file's name filename: 'bundle.js', // Where the output file will be placed. Resolves to // the "dist" folder in the directory of the project path: path.resolve(__dirname, 'dist'), // Configures the "crossorigin" attribute for resources // with subresource integrity injected crossOriginLoading: 'anonymous' }, // Used for configuring how various modules (files that // are imported) will be treated modules: { // Configures how specific module types are handled rules: [ { // Regular expression to test for the file extension. // These loaders will only be activated if they match // this expression. test: /\.css$/, // An array of loaders that will be applied to the file use: ['style-loader', 'css-loader'], // Prevents the accidental loading of files within the // "node_modules" folder exclude: /node_modules/ } ] }, // webpack plugins alter the function of webpack itself plugins: [ // Plugin that will inject integrity hashes into index.html new SriPlugin({ // The hash functions used (eg // <script integrity="sha256- ... sha384- ..." ... hashFuncNames: ['sha384'] }), // Creates an HTML file along with the bundle. We will // inject the subresource integrity information into // the resources using webpack-subresource-integrity new HTMLWebpackPlugin({ // The file that will be injected into. We can use // EJS templating within this file, too template: path.resolve(__dirname, 'src', 'index.ejs'), // Whether or not to insert scripts and other resources // into the file dynamically. For our example, we will // enable this. inject: true }) ] };

Membuat template

Kita perlu membuat template untuk memberi tahu webpack apa yang harus disuntikkan ke bundel dan informasi integritas subsumber daya. Buat file bernama index.ejs :

 <!DOCTYPE html> <html> <body></body> </html>

Sekarang, buat index.js di folder dengan skrip berikut:

 // Imports the CSS stylesheet import './styles.css' alert('Hello, world!');

Membangun bundel

Ketik npm run build di terminal. Anda akan melihat bahwa sebuah folder bernama dist telah dibuat, dan di dalamnya, sebuah file bernama index.html yang terlihat seperti ini:

 <!DOCTYPE HTML> <html><head><script defer src="bundle.js" integrity="sha384-lb0VJ1IzJzMv+OKd0vumouFgE6NzonQeVbRaTYjum4ql38TdmOYfyJ0czw/X1a9b" crossorigin="anonymous"> </script></head> <body> </body> </html>

CSS akan disertakan sebagai bagian dari file bundle.js

Ini tidak akan berfungsi untuk file yang dimuat dari server eksternal, juga tidak, karena file lintas asal yang perlu diperbarui terus-menerus akan rusak dengan integritas subsumber daya yang diaktifkan.

Terima kasih sudah membaca!

Itu saja untuk yang satu ini. Integritas subsumber daya adalah tambahan yang sederhana dan efektif untuk memastikan Anda hanya memuat apa yang Anda harapkan dan melindungi pengguna Anda; dan ingat, keamanan lebih dari satu solusi, jadi selalu cari cara lain untuk menjaga keamanan situs web Anda.


Posting Mengamankan Situs Web Anda Dengan Integritas Subresource muncul pertama kali di CSS-Tricks .

Anda dapat mendukung Trik-CSS dengan menjadi Pendukung MVP .

June 14, 2021

codeorayo

Ampuh! Ini rahasia mengembangkan aplikasi secara instan, tinggal download dan kembangkan. Gabung sekarang juga! Premium Membership [PRIVATE] https://premium.codeorayo.com

Leave a Reply

Your email address will not be published. Required fields are marked *