Penulis artikel, terjemahan yang kami terbitkan hari ini, mengatakan bahwa React adalah perpustakaan favoritnya untuk membuat antarmuka interaktif. Bereaksi mudah digunakan dan dilindungi dengan cukup baik. Namun, ini tidak berarti bahwa Bereaksi aplikasi sepenuhnya kebal. Sangat mudah untuk jatuh ke dalam ketenangan pikiran yang tidak masuk akal, setelah memutuskan bahwa Anda tidak dapat khawatir tentang serangan XSS karena fakta bahwa proyek tersebut menggunakan React.
Kerentanan dalam Bereaksi paling sering terjadi ketika pengembang berpikir bahwa ia menggunakan mekanisme perlindungan dari perpustakaan ini, meskipun pada kenyataannya ternyata tidak demikian. Oleh karena itu, penting untuk mengevaluasi dengan benar kemampuan React, dan untuk mengetahui tugas-tugas apa yang perlu diselesaikan oleh seorang programmer.

Hari ini kita akan berbicara tentang kerentanan Bereaksi khas, bagaimana menemukan mereka selama peninjauan kode, dan bagaimana mempertahankannya.
Contoh skrip lintas situs (sangat singkat) pertama
Cross site scripting (XSS) adalah kerentanan klien yang dapat menyebabkan masalah serius. Serangan XSS terjadi ketika seorang penyerang dapat menipu situs web dan memaksanya untuk mengeksekusi kode JavaScript sewenang-wenang di browser penggunanya.
Serangan XSS yang direfleksikan dilakukan melalui tautan yang berisi informasi tekstual yang diproses oleh browser dalam bentuk kode. Misalnya, ini adalah bidang formulir di mana, di sisi klien, teks permintaan khusus dimasukkan.
Serangan XSS yang disimpan adalah situasi di mana penyerang memiliki akses ke server, dan ketika kode yang dieksekusi di server menghasilkan apa yang sampai ke halaman web klien. Vektor khas dari serangan tersebut adalah mengunggah komentar dan gambar ke server.
Samy worm mengeksploitasi kerentanan MySSpace XSS. Itu adalah salah satu virus yang paling cepat menyebar sepanjang masa.
Situs web yang rentan dapat mengekspos penggunanya terhadap pencurian kata sandi atau data pribadi. Dan ini adalah cara biasa mengeksploitasi kerentanan lainnya. Skrip berbahaya paling sering digunakan untuk mengirim spam dan untuk mengarahkan pengguna ke situs penipuan. Ini dapat merusak reputasi dan kinerja SEO situs yang berhasil diserang.
Kerentanan # 1: kontrol atas keadaan awal halaman, yang digunakan selama rendering server
Terkadang, ketika kita membentuk keadaan awal suatu halaman, kita, yang berbahaya, membuat dokumen berdasarkan string JSON. Kerentanan dalam kode ini terlihat seperti ini:
<script>window.__STATE__ = ${JSON.stringify({ data })}</script>
Ini berbahaya karena fakta bahwa metode
JSON.stringify()
, tanpa "memikirkan" apa pun, mengonversi data apa pun yang diberikan kepadanya dalam bentuk string (selama itu adalah data JSON yang valid), yang merupakan akan ditampilkan di halaman. Jika
{ data }
memiliki bidang yang dapat diedit pengguna yang tidak dipercaya, seperti nama pengguna atau informasi pengguna, sesuatu seperti yang berikut ini dapat disematkan dalam bidang tersebut:
{ username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }
Pola ini sering digunakan dalam rendering sisi server dari aplikasi Bereaksi yang menggunakan Redux. Dia hadir dalam dokumentasi resmi Redux, dan sebagai hasilnya, banyak tutorial dan contoh templat aplikasi yang dapat ditemukan di GitHub masih menggunakannya.
Tidak percaya Kemudian lihat sendiri. Cari Google untuk teks "bereaksi aplikasi contoh rendering sisi server" dan coba serangan ini pada salah satu hasil pencarian dari halaman pertama.
β Identifikasi kerentanan selama peninjauan kode
Cari panggilan ke metode
JSON.stringify()
yang menerima variabel yang mungkin berisi data yang tidak tepercaya dalam tag
script
. Berikut adalah contoh yang digunakan dalam dokumentasi Redux:
function renderFullPage(html, preloadedState) { return ` <!doctype html> <html> <head> <title>Redux Universal Example</title> </head> <body> <div id="root">${html}</div> <script> window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)} </script> <script src="/static/bundle.js"></script> </body> </html> ` }
Dan berikut ini adalah sepotong kode dari contoh aplikasi yang ditemukan di GitHub:
function htmlTemplate( reactDom, reduxState, helmetData ) { return ` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ${ helmetData.title.toString( ) } ${ helmetData.meta.toString( ) } <title>React SSR</title> <link rel="stylesheet" type="text/css" href="./styles.css" /> </head> <body> <div id="app">${ reactDom }</div> <script> window.REDUX_DATA = ${ JSON.stringify( reduxState ) } </script> <script src="./app.bundle.js"></script> </body> </html> `; }
Terkadang menemukan kerentanan ini sedikit lebih sulit. Kode berikut juga akan berubah menjadi tidak aman - jika pelolosan yang benar dari
context.data
tidak dilakukan:
const RenderedApp = htmlData.replace('{{SSR}}', markup) .replace('<meta-head/>', headMarkup) .replace('{{data}}', new ArrayBuffer(JSON.stringify(context.data)).toString('base64'))
Saat melakukan rendering sisi server, perhatikan apa yang sebenarnya diberikan. Jika apa yang dimasukkan pengguna tidak terlindungi dengan baik dan ditampilkan di DOM, ini bisa berbahaya.
β Perlindungan
Salah satu opsi untuk melindungi dari kerentanan ini adalah dengan menggunakan modul npm
serialize-javascript
, yang dirancang untuk melindungi output JSON. Jika Anda melakukan rendering server di lingkungan non-Node.js, maka Anda harus memilih paket yang sesuai untuk bahasa Anda.
Ini adalah perintah untuk menginstal modul:
$ npm install --save serialize-javascript
Setelah itu, Anda perlu mengimpornya ke file dan menulis ulang kode yang sebelumnya rentan berurusan dengan
window
berikut:
<script>window.__STATE__ = ${ serialize( data, { isJSON: true } ) }</script>
Ini adalah artikel yang bagus tentang hal ini.
Kerentanan β2: tautan berbahaya
Tag
<a>
dapat memiliki atribut
href
, yang berisi tautan ke halaman situs lain, ke situs lain, ke suatu tempat di halaman saat ini. Tautan dapat berisi skrip yang terlihat seperti ini:
javascript: stuff()
. Jika Anda tidak tahu tentang fitur HTML ini, coba sekarang juga dengan menyalin kode berikut ke dalam baris browser:
data:text/html, <a href="javascript: alert('hello from javascript!')" >click me</a>
Untuk pengembang web, ini berarti bahwa jika konten tautan diatur berdasarkan data yang dimasukkan oleh pengguna, penyerang dapat menambahkan kode berbahaya mulai dengan
javascript:
ke data ini. Kemudian, jika pengguna mengklik tautan yang buruk, skrip penyerang akan diluncurkan di browser.
Kerentanan ini jelas bukan hanya karakteristik dari Bereaksi, tetapi itu adalah salah satu masalah yang sering ditemui pengembang Bereaksi ketika mereka mengharapkan nilai yang sesuai untuk secara otomatis lolos dengan benar. Perlu dicatat bahwa dalam versi Bereaksi
masa depan masalah ini akan menjadi kurang akut.
β Identifikasi kerentanan selama peninjauan kode
Dapatkah pengguna proyek menambahkan tautan ke halaman yang diklik pengguna lain? Jika demikian, coba tambahkan "tautan" ke halaman seperti berikut:
javascript: alert("You are vulnerable to XSS!")
Jika kotak pesan yang sesuai ditampilkan dengan mengklik tautan, ini berarti proyek tersebut rentan terhadap serangan XSS. Coba ini di mana pun Anda dapat menambahkan tautan. Kemungkinan tidak semua tempat seperti itu rentan.
β Perlindungan
Perlindungan terhadap kerentanan ini tidak hanya cocok untuk proyek Bereaksi. Apa yang sebenarnya perlu dilakukan tergantung pada aplikasi. Selain itu, Anda mungkin perlu melakukan koreksi pada server.
Anda mungkin berpikir bahwa untuk menyelesaikan masalah, cukup menghapus
javascript:
awalan dari data. Ini adalah contoh penggunaan strategi daftar hitam, yang tidak dapat dianggap berhasil dalam
membersihkan data . Peretas memiliki cara yang cerdik untuk mem-bypass filter semacam itu, jadi alih-alih memindahkan (atau sebagai tambahan), pastikan bahwa tautan tersebut menggunakan protokol daftar putih (misalnya,
http:
dan keluar dari entitas HTML.
Berikut adalah artikel terperinci tentang topik ini mengenai perisai properti yang dapat dikendalikan oleh penyerang.
Strategi lain yang dapat menambahkan tingkat perlindungan tambahan ke proyek adalah menggunakan mekanisme untuk membuka tautan khusus di tab browser baru. Namun, saya tidak akan merekomendasikan menggunakan strategi ini sebagai satu-satunya "garis pertahanan" proyek. Membuka
javascript:
tautan di tab baru adalah contoh perilaku elemen halaman yang tidak standar. Sebagian besar browser akan menjalankan skrip di tab kosong tanpa membahayakan pengguna, tetapi ini tidak dijamin, dan Anda mungkin bisa menyiasatinya, yang tergantung pada browser.
Pertimbangkan untuk menggunakan komponen
UserLink khusus, yang akan mengarah pada fakta bahwa tag
<a>
rentan cenderung untuk sampai ke halaman proyek Anda di masa mendatang. Selain itu, ada baiknya menambahkan beberapa tes dan aturan linting untuk proyek, yang bertujuan mengidentifikasi kode yang berpotensi berbahaya dan mencegahnya masuk ke produksi.
Tautan bukan satu-satunya entitas yang dapat digunakan dengan cara ini. Tetapi mereka adalah target serangan yang paling mungkin dalam aplikasi Bereaksi. Elemen apa pun bisa rentan terhadap serangan ini jika penyerang dapat mengontrol nilai
URI
-nya. Kemungkinan lain untuk melakukan serangan ini, misalnya, adalah desain tampilan. Daftar lengkap atribut yang mungkin mengandung URI dapat ditemukan dalam daftar
ini menggunakan kata kunci
%URI
menggunakan pencarian browser (
Ctrl+F
).
Kerentanan # 3: kesalahpahaman arti konstruksi berbahayaSetInnerHtml
Saya sangat berterima kasih untuk Bereaksi bahwa peringatan keamanan secara langsung atas nama metode. Ini adalah nama
dangerouslySetInnerHTML
. Terlepas dari peringatan ini, kita masih sering dihadapkan dengan fakta bahwa pengembang mengambil risiko dengan melakukan operasi yang tidak aman. Hal yang sama dapat dikatakan tentang
eval()
.
Pertimbangkan contoh berikut yang saya temukan di situs dari halaman pertama hasil pencarian Google:
<script dangerouslySetInnerHTML={{ __html: `window.__PRELOADED_STATE__ = ${JSON.stringify(initialState)};`}}></script>
Ini adalah contoh kerentanan No. 1, tetapi dengan satu fitur yang harus segera menarik perhatian pada fakta bahwa ada sesuatu yang salah di sini. Di mana saya menemukan ini, sebuah upaya dilakukan untuk menjelaskan: "Kami menggunakan
berbahayaSetInnerHTML sebagai metode pembersihan data dan mencegah serangan XSS." Ya tidak! Ini salah. Jangan lakukan itu. Untuk informasi lebih lanjut tentang
dangerouslySetInnerHTML
, baca dokumentasi Bereaksi.
Contoh lain bahwa ini benar-benar terjadi sepanjang waktu adalah bagaimana anggota tim yang sama menemukan bahwa mereka memiliki
kerentanan ketika mereka menambahkan markup Markdown ke halaman menggunakan
dangerouslySetInnerHTML
. Untuk melindungi diri mereka dari ini di masa depan, mereka mulai menggunakan aturan khusus untuk menyisir.
β Identifikasi kerentanan selama peninjauan kode
Sebelum mengirim permintaan tarikan atau melakukan operasi penggabungan, penting untuk mencari kode untuk
dangerouslySetInnerHTML
eval
dan string
eval
(Saya juga mencari perintah
console.log
dengan cara ini) atau menggunakan aturan linter yang sesuai.
β Perlindungan
Pastikan bahwa dalam semua kasus menggunakan metode
dangerouslySetInnerHTML
, hanya data yang dapat Anda percaya yang dimuat ke halaman. Bagaimana Anda tahu jika data dapat dipercaya? Jika sesuatu tidak datang dari Anda, itu bisa menjadi ancaman. Ini termasuk data yang diunduh dari API eksternal dan apa yang dikeluarkan menggunakan alat Markdown.
Catatan Spoofing Komponen
Pada 2015,
seseorang menemukan bahwa Anda dapat menipu komponen dengan mengirimkan JSON ke komponen yang mengharapkan teks. Saya hanya dapat menemukan satu kasus pesan spoofing komponen dan
diskusi panjang yang disebabkan oleh pesan ini. Diskusi berfokus pada apa yang bertanggung jawab React untuk mencegah serangan XSS. Akibatnya, pengembang Bereaksi merilis
perbaikan yang tampaknya telah membantu memperbaiki kerentanan ini.
Saya memutuskan untuk tidak memasukkan cerita tentang kerentanan ini dalam artikel, tetapi topik ini mungkin menarik untuk penelitian lebih lanjut.
Catatan SSR
Kerentanan rendering server sangat luas karena fakta bahwa ia ada dalam dokumentasi Redux dan, sebagai akibatnya, tersebar di banyak materi lainnya. Masalah ini diperbaiki pada tahun 2016. Tetapi bahkan hari ini, setelah tiga tahun, panduan pemula yang tersebar di internet masih mengajarkan apa yang tidak boleh Anda ajarkan.
Ngomong-ngomong, ini pekerjaan rumah Anda: temukan contoh masalah ini di GitHub dan kirim permintaan tarik untuk memperbaikinya.
Berikut ini sebuah contoh .
Bersama-sama kita bisa sekali dan untuk selamanya menghilangkan kerentanan ini!
Pembaca yang budiman! Sudahkah Anda mengalami serangan pada proyek Bereaksi Anda?
