Pada kesempatan kali ini, kita akan mempelajari cara melindungi aplikasi web–khususnya yang dibuat dengan Codeigniter–dari serangan XSS
Selain itu, kita juga akan mempelajari cara melakukan serangan XSS agar dapat mengetahui cara menghindarinya
Baiklah
Mari kita mulai
Apa itu XSS?
XSS adalah singkatan dari skrip lintas situs
Alasan singkatan yang digunakan adalah XSS bukan CSS, karena CSS sudah digunakan untuk cascade style sheet
Jadi X adalah singkatan dari Cross
XSS merupakan salah satu bentuk serangan terhadap aplikasi web yang dilakukan dengan menginjeksi kode javascript dari sisi client.
Dampak yang dapat ditimbulkan XSS
- Keamanan aplikasi web dapat dilewati;
- Data pengguna dapat dicuri;
- Halaman yang terkena XSS dapat digunakan sebagai media Phishing;
- dan lain-lain
Cara Mengatasi XSS di Codeigniter
"Untuk menangkap pencuri, kita harus berpikir seperti pencuri"
Mari pelajari cara melakukan serangan XSS untuk menghindarinya
1. XSS yang dipantulkan
Ini adalah jenis serangan XSS yang sering dilakukan penyerang
Ini biasanya terjadi pada input parameter string kueri yang kami tampilkan
Contoh
Misalkan kita memiliki fitur pencarian seperti ini
<?php class Search extends CI_Controller { public function index() { $data["keyword"] = $this->input->get("keyword"); // do search and render result to view $this->load->view('search', $data); } }
Kemudian pada tampilan, kita tampilkan index.php/search/?keyword=<script>alert('hacked!')</script>_0 yang diinputkan seperti ini
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>
Sekilas tidak ada masalah dengan kode ini
Tapi coba masukan index.php/search/?keyword=<script>alert('hacked!')</script>_1 dengan kode Javascript seperti ini
index.php/search/?keyword=<script>alert('hacked!')</script>_
Jadi hasilnya
Bagaimana mengatasi serangan ini?
✅ Solusinya
Gunakan fungsi index.php/search/?keyword=<script>alert('hacked!')</script>_2 pada tampilan untuk menampilkan variabel index.php/search/?keyword=<script>alert('hacked!')</script>0
<p>Hasil pencarian dengan kata kunci <?= htmlentities($keyword) ?></p> <p>Hasil: ...</p>
Jadi sekarang halaman ini tidak akan bisa diserang oleh XSS
Tapi jangan senang dulu
Masih ada jenis serangan XSS lainnya
2. XSS tersimpan
XSS Tersimpan adalah serangan XSS yang dilakukan dengan menyuntikkan XSS pada input yang disimpan dalam database
Sebenarnya tidak harus database, yang penting inputnya disimpan di suatu tempat
Nanti saat ditampilkan di halaman tampilan. kode injeksi XSS akan dieksekusi
Sebagai contoh
Misalkan kita membuat fitur untuk aplikasi lowongan kerja. Masukan yang kita butuhkan untuk menambah lowongan baru adalah sebagai berikut
- index.php/search/?keyword=<script>alert('hacked!')</script>_4 nama atau jabatan;
- index.php/search/?keyword=<script>alert('hacked!')</script>5 alamat URL poster;
- index.php/search/?keyword=<script>alert('hacked!')</script>_6 alamat pendaftaran lowongan kerja
Bentuk kode di Controllernya seperti ini
📜 index.php/search/?keyword=<script>alert('hacked!')</script>_7
<?php class Jobvacancy extends CI_Controller { public function addjob() { if ($this->input->method() === "post") { $data["job"] = $this->input->post(); // di sini biasanya dilakukan penyimpanan ke database return $this->load->view("list_job", $data); } $this->load->view('add_job_form'); } }
dan ini adalah kode untuk tampilan
📜 index.php/search/?keyword=<script>alert('hacked!')</script>_8
<h1><?= $job["name"] ?></h1> <img src='<?= $job["job_image_url"] ?>' /> <br> <a href='<?= $job["job_url"] ?>'>Link Pendaftaran</a>
📜 index.php/search/?keyword=<script>alert('hacked!')</script>_9
<form action="" method="post"> <label for="name">Vacancy Job name</label> <input type="text" name="name" > <br> <label for="job_image_url">Image URL</label> <input type="text" name="job_image_url"> <br> <label for="job_url">Job URL</label> <input type="text" name="job_url"> <br> <input type="submit" value="Simpan"> </form>
Ini adalah hasil ketika kita input data yang benar
Sekarang coba masukkan index.php/search/?keyword=<script>alert('hacked!')</script>_4 atau judul loker dengan kode javascript
<script>alert('hacked')</script>
Untuk URL biarkan kosong saja
Jadi hasilnya
Serangan ini sama persis dengan Reflected XSS, bedanya injeksi akan disimpan di database
Pada contoh di atas kita tidak menggunakan database. Namun dalam praktiknya, kami pasti akan menyimpannya ke database untuk menginput data ini
Lalu apa solusi yang bisa kita lakukan?
✅ Solusi
Solusinya sama dengan XSS Reflected, yaitu kita harus menampilkan output dengan fungsi index.php/search/?keyword=<script>alert('hacked!')</script>2
Jadi di lihat 📜 <p>Hasil pencarian dengan kata kunci <?= htmlentities($keyword) ?></p> <p>Hasil: ...</p>_2 kita bisa mengubahnya seperti ini
<h1><?= htmlentities($job["name"]) ?></h1> <img src='<?= htmlentities($job["job_image_url"]) ?>' /> <br> <a href='<?= htmlentities($job["job_url"]) ?>'>Link Pendaftaran</a>
Hasil
Besar
Tapi jangan senang dulu
Karena ini masih belum aman
Mengapa?
Kita harus mengetahui keluaran pada atribut <p>Hasil pencarian dengan kata kunci <?= htmlentities($keyword) ?></p> <p>Hasil: ...</p>3 pada gambar dan <p>Hasil pencarian dengan kata kunci <?= htmlentities($keyword) ?></p> <p>Hasil: ...</p>4 pada tautan
Mereka bisa memberikan suntikan seperti ini
x' onerror='alert("Hacked")'
Injeksi ini akan membuat atribut baru bernama <p>Hasil pencarian dengan kata kunci <?= htmlentities($keyword) ?></p> <p>Hasil: ...</p>5 yang berfungsi untuk menjalankan kode javascript
Atau kita juga bisa menggunakan <p>Hasil pencarian dengan kata kunci <?= htmlentities($keyword) ?></p> <p>Hasil: ...</p>6 seperti ini
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>0
Mari mencoba
Hasil
Lihat itu. belum 100% aman hehe
Lalu bagaimana cara mengatasi hal tersebut?
✅ Solusi
Sebenarnya kita bisa menggunakan tanda kutip ganda pada atribut HTML seperti ini
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>1
Atribut yang dihasilkan akan terlihat seperti ini
Apakah ini aman?
Belum. 😄
Saya melakukan percobaan ini di browser versi terbaru. Mungkin saja di browser versi lama masih akan terpengaruh
Apa solusinya?
Kita dapat menggunakan konstanta <p>Hasil pencarian dengan kata kunci <?= htmlentities($keyword) ?></p> <p>Hasil: ...</p>7 pada parameter index.php/search/?keyword=<script>alert('hacked!')</script>2 untuk menyandikan tanda kutip. Baik ganda maupun tunggal
Jadi kode tampilannya akan seperti ini
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>2
Kita bisa melihat hasilnya di View Source
Masalah injeksi tanda kutip telah diperbaiki
Apakah ini aman?
Belum. 🤣
Serangan injeksi berikutnya, saat pengguna memasukkan
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>_3
Biasanya jika nilai ini diberikan pada link, maka browser akan menjalankan kode javascript yang diberikan
Coba gunakan masukan itu
Hasil
Kami sudah menggunakan index.php/search/?keyword=<script>alert('hacked!')</script>_2, tapi yang ini bisa lewat
Apa solusinya?
✅ Solusi
Solusi yang bisa kita lakukan untuk mengatasi serangan ini adalah dengan melakukan validasi data. Baik di sisi klien maupun server
Belajar juga
- Cara Validasi data di Codeigniter
Mari kita coba lakukan validasi di sisi server terlebih dahulu
Ubah Controller menjadi seperti ini
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>_4
Kemudian ubah tampilan untuk form menjadi seperti ini
📜 index.php/search/?keyword=<script>alert('hacked!')</script>_9
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>5
Hasil
Besar
Dengan cara ini aman
Validasi saja di sisi klien
Validasi di sisi klien dapat dilakukan dengan atribut HTML. Kita dapat mengubah nilai pada atribut <?php class Jobvacancy extends CI_Controller { public function addjob() { if ($this->input->method() === "post") { $data["job"] = $this->input->post(); // di sini biasanya dilakukan penyimpanan ke database return $this->load->view("list_job", $data); } $this->load->view('add_job_form'); } }_1 menjadi <?php class Jobvacancy extends CI_Controller { public function addjob() { if ($this->input->method() === "post") { $data["job"] = $this->input->post(); // di sini biasanya dilakukan penyimpanan ke database return $this->load->view("list_job", $data); } $this->load->view('add_job_form'); } }2 dan juga menambahkan <?php class Jobvacancy extends CI_Controller { public function addjob() { if ($this->input->method() === "post") { $data["job"] = $this->input->post(); // di sini biasanya dilakukan penyimpanan ke database return $this->load->view("list_job", $data); } $this->load->view('add_job_form'); } }3 untuk validasi dengan regex
Silakan belajar juga
- Apa itu Regex?
Nah sekarang kita ubah view codenya menjadi seperti ini
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>6
Hasil
Sekarang saya merasa aman
Tapi jangan dikira 100% aman, hehe
Karena masih ada bentuk serangan XSS lainnya
3. XSS Berbasis DOM
XSS Berbasis DOM adalah jenis serangan XSS yang injeksinya dilakukan di DOM (Document Object Model)
Apa itu DOM?
Silahkan belajar di
- tutorial javascript. Apa itu DOM?
Untuk mendemonstrasikan serangan ini, mari ubah tampilan pada form <?php class Jobvacancy extends CI_Controller { public function addjob() { if ($this->input->method() === "post") { $data["job"] = $this->input->post(); // di sini biasanya dilakukan penyimpanan ke database return $this->load->view("list_job", $data); } $this->load->view('add_job_form'); } }4 menjadi seperti ini
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>7
Kami menambahkan fitur untuk pratinjau gambar berdasarkan masukan URL gambar
Jika URL yang dimasukkan valid, maka akan muncul seperti ini
Berdasarkan kode javascript yang kami buat. Kami menampilkan gambar dengan manipulasi DOM
Hal ini tentunya akan membuat kita bisa melakukan XSS berbasis DOM
Ingin bukti?
Silakan masukkan injeksi XSS berikut di URL gambar
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>_8
Jadi hasilnya
Itu benar. 😆
Meskipun kami telah melakukan validasi di sisi klien dan server
Lalu apa solusinya?
✅ Solusi
Solusi untuk menghindari XSS berbasis DOM sebenarnya hampir sama dengan Reflected XSS
Perbedaannya adalah bahwa XSS berbasis DOM dilakukan pada klien atau dalam Javascript. tidak dalam PHP atau kode server
Namun, fungsi index.php/search/?keyword=<script>alert('hacked!')</script>_2 di javascript belum ada. Kita bisa membuat fungsi ini secara manual, atau kita juga bisa menggunakan library seperti underscore. js dengan fungsi <?php class Jobvacancy extends CI_Controller { public function addjob() { if ($this->input->method() === "post") { $data["job"] = $this->input->post(); // di sini biasanya dilakukan penyimpanan ke database return $this->load->view("list_job", $data); } $this->load->view('add_job_form'); } }6
Ada juga perpustakaan DOMPurify yang khusus menangani XSS
OWASP sendiri juga menawarkan perpustakaan ESAPI untuk keluar dari HTML dalam javascript
Kamu bisa membaca
- Cara Mitigasi XSS Berbasis DOM menurut OWASP
Solusi lain adalah memicu validator HTML saat bidang input dimasukkan
Misalnya seperti ini
<p>Hasil pencarian dengan kata kunci <?= $keyword ?></p> <p>Hasil: ...</p>_9
Jadi gambar pratinjau tidak akan ditampilkan selama nilai URL yang diberikan tidak valid
4. Self-XSS
Teknik XSS ini sulit diatasi dari kode aplikasi. Karena dilakukan oleh pengguna sendiri
Misalnya ini
Penyerang melakukan rekayasa sosial untuk memasarkan pengguna
Penyerang. "Hai, saya punya kode rahasia untuk mendapatkan diskon 99%"
Korban. "Betulkah?
Penyerang. "Buka aplikasi dari Google Chrome di Laptop, masuk ke halaman checkout, klik kanan, lalu pilih inspect element, lalu masuk ke Console. Setelah itu paste kode ini <?php class Jobvacancy extends CI_Controller { public function addjob() { if ($this->input->method() === "post") { $data["job"] = $this->input->post(); // di sini biasanya dilakukan penyimpanan ke database return $this->load->view("list_job", $data); } $this->load->view('add_job_form'); } }7, setelah itu tekan Enter. "
Korban. "Wah, kamu bisa mencobanya. ”
Beberapa hari kemudian
Korban. "Kenapa saldo saya hilang 😭?. ”
Nah kira-kira seperti itulah skenario Self XSS
Injeksi XSS dilakukan oleh pengguna yang menjadi korban Rekayasa Sosial
Lalu bagaimana cara mengatasinya?
✅ Solusi
Seperti yang saya katakan, Self XSS sulit diatasi dari kode aplikasi. Salah satu cara yang dapat dilakukan adalah memberikan instruksi kepada pengguna untuk tidak menjalankan kode apapun di browser Console Javascript
Kita bisa meniru cara Facebook memberikan edukasi dengan menampilkan pesan ini di konsol Javascript
5. XSS bermutasi (mXSS)
Teknik serangan XSS ini sangat jarang digunakan dan sulit dideteksi. Karena baru ditemukan pada tahun 2019