Saya mencoba memahami seluruh masalah dengan CSRF dan cara yang tepat untuk mencegahnya. (Sumber yang telah saya baca, pahami, dan setujui dengan: Lembar Cegah Pencegahan CSRF OWASP , Pertanyaan tentang CSRF .)
Seperti yang saya pahami, kerentanan sekitar CSRF diperkenalkan oleh asumsi bahwa (dari sudut pandang server web) cookie sesi yang valid dalam permintaan HTTP masuk mencerminkan keinginan pengguna yang diautentikasi. Tetapi semua cookie untuk domain asal secara ajaib dilampirkan ke permintaan oleh browser, jadi benar-benar semua server dapat menyimpulkan dari kehadiran cookie sesi yang valid dalam permintaan adalah bahwa permintaan tersebut berasal dari browser yang memiliki sesi terotentikasi; lebih lanjut tidak dapat menganggap apa pun tentang kodeberjalan di browser itu, atau apakah itu benar-benar mencerminkan keinginan pengguna. Cara untuk mencegah ini adalah dengan memasukkan informasi otentikasi tambahan ("token CSRF") dalam permintaan, yang dilakukan dengan beberapa cara selain penanganan cookie otomatis browser. Secara longgar, cookie sesi mengotentikasi pengguna / browser dan token CSRF mengotentikasi kode yang berjalan di browser.
Singkatnya, jika Anda menggunakan cookie sesi untuk mengautentikasi pengguna aplikasi web Anda, Anda juga harus menambahkan token CSRF untuk setiap respons, dan memerlukan token CSRF yang cocok di setiap permintaan (yang bermutasi). Token CSRF kemudian melakukan bolak-balik dari server ke browser kembali ke server, membuktikan ke server bahwa halaman yang membuat permintaan disetujui oleh (dihasilkan oleh, bahkan) server itu.
Ke pertanyaan saya, yaitu tentang metode transportasi spesifik yang digunakan untuk token CSRF pada perjalanan pulang pergi itu.
Tampaknya umum (misalnya dalam AngularJS , Django , Rails ) untuk mengirim token CSRF dari server ke klien sebagai cookie (yaitu dalam header Set-Cookie), dan kemudian memiliki Javascript di klien mengikisnya keluar dari cookie dan melampirkannya sebagai header XSRF-TOKEN yang terpisah untuk mengirim kembali ke server.
(Metode alternatif adalah metode yang direkomendasikan oleh misalnya Express , di mana token CSRF yang dihasilkan oleh server dimasukkan dalam badan respons melalui ekspansi templat sisi-server, dilampirkan langsung ke kode / markup yang akan memasoknya kembali ke server, misalnya sebagai input formulir tersembunyi. Contoh itu adalah web yang lebih 1.0-ish cara melakukan sesuatu, tetapi akan menggeneralisasi baik untuk klien yang lebih berat JS.)
Mengapa Set-Cookie sangat umum digunakan sebagai transportasi hilir untuk token CSRF / mengapa ini ide yang bagus? Saya membayangkan penulis dari semua kerangka kerja ini mempertimbangkan pilihan mereka dengan hati-hati dan tidak salah. Tetapi pada pandangan pertama, menggunakan cookie untuk mengatasi apa yang pada dasarnya pembatasan desain pada cookie tampaknya bodoh. Bahkan, jika Anda menggunakan cookie sebagai transportasi pulang pergi (Set-Cookie: header hilir untuk server untuk memberitahu browser token CSRF, dan Cookie: header hulu untuk browser untuk mengembalikannya ke server) Anda akan memperkenalkan kembali kerentanan Anda sedang mencoba untuk memperbaikinya.
Saya menyadari bahwa kerangka kerja di atas tidak menggunakan cookie untuk seluruh perjalanan pulang pergi untuk token CSRF; mereka menggunakan Set-Cookie downstream, lalu sesuatu yang lain (misalnya header X-CSRF-Token) upstream, dan ini tidak menutup kerentanan. Tetapi bahkan menggunakan Set-Cookie sebagai transportasi hilir berpotensi menyesatkan dan berbahaya; browser sekarang akan melampirkan token CSRF untuk setiap permintaan termasuk permintaan XSRF berbahaya asli; paling-paling itu membuat permintaan lebih besar dari yang seharusnya dan paling buruk beberapa kode server yang bermaksud baik tetapi salah arah mungkin benar-benar mencoba menggunakannya, yang akan sangat buruk. Dan lebih jauh lagi, karena penerima token CSRF yang sebenarnya dimaksudkan adalah Javascript sisi klien, itu artinya cookie ini tidak dapat dilindungi hanya dengan http.
Jawaban:
Alasan yang bagus, yang telah Anda sentuh, adalah bahwa setelah cookie CSRF diterima, maka cookie tersebut akan tersedia untuk digunakan di seluruh aplikasi dalam skrip klien untuk digunakan dalam bentuk reguler dan POS AJAX. Ini akan masuk akal dalam aplikasi berat JavaScript seperti yang dipekerjakan oleh AngularJS (menggunakan AngularJS tidak mengharuskan aplikasi tersebut menjadi aplikasi satu halaman, jadi akan berguna jika negara perlu mengalir di antara permintaan halaman berbeda di mana nilai CSRF biasanya tidak dapat bertahan di browser).
Pertimbangkan skenario dan proses berikut dalam aplikasi tipikal untuk beberapa pro dan kontra dari setiap pendekatan yang Anda jelaskan. Ini didasarkan pada Pola Token Sinkronisasi .
Meminta Pendekatan Badan
Keuntungan:
Kekurangan:
Header HTTP Khusus (hilir)
Keuntungan:
Kekurangan:
Header HTTP Khusus (hulu)
Keuntungan:
Kekurangan:
Header HTTP Khusus (hulu & hilir)
Keuntungan:
Kekurangan:
Set-Cookie
Keuntungan:
Kekurangan:
Jadi pendekatan cookie cukup dinamis yang menawarkan cara mudah untuk mengambil nilai cookie (permintaan HTTP apa pun) dan menggunakannya (JS dapat menambahkan nilai ke formulir apa pun secara otomatis dan dapat digunakan dalam permintaan AJAX baik sebagai header atau sebagai nilai bentuk). Setelah token CSRF telah diterima untuk sesi ini, tidak perlu untuk memperbaruinya karena penyerang yang menggunakan eksploitasi CSRF tidak memiliki metode untuk mengambil token ini. Jika pengguna jahat mencoba membaca token CSRF pengguna dalam salah satu metode di atas maka ini akan dicegah oleh ), maka token ini tidak akan dikaitkan dengan akun pengguna yang sama karena cookie sesi autentikasi korban akan hilang dari permintaan ( itu akan menjadi penyerang - karena itu tidak akan dikaitkan sisi server dengan sesi korban). Kebijakan Asal yang Sama . Jika pengguna jahat mencoba mengambil sisi server token CSRF (mis. Via
curl
Selain Pola Sinkronisasi Token, ada juga Cookie Kirim GandaMetode pencegahan CSRF, yang tentu saja menggunakan cookie untuk menyimpan jenis token CSRF. Ini lebih mudah untuk diterapkan karena tidak memerlukan keadaan sisi server apa pun untuk token CSRF. Token CSRF sebenarnya bisa menjadi cookie otentikasi standar saat menggunakan metode ini, dan nilai ini dikirimkan melalui cookie seperti biasa dengan permintaan, tetapi nilainya juga diulang dalam bidang atau tajuk tersembunyi, yang tidak dapat direplikasi oleh penyerang sebagai mereka tidak dapat membaca nilai di tempat pertama. Akan disarankan untuk memilih cookie lain, selain cookie otentikasi sehingga cookie otentikasi dapat diamankan dengan ditandai HttpOnly. Jadi ini adalah alasan umum mengapa Anda akan menemukan pencegahan CSRF menggunakan metode berbasis cookie.
sumber
Menggunakan cookie untuk memberikan token CSRF kepada klien tidak memungkinkan serangan yang berhasil karena penyerang tidak dapat membaca nilai cookie dan oleh karena itu tidak bisa meletakkannya di tempat yang memerlukan validasi CSRF di sisi server.
Penyerang akan dapat menyebabkan permintaan ke server dengan cookie token auth dan cookie CSRF di header permintaan. Tetapi server tidak mencari token CSRF sebagai cookie di header permintaan, itu mencari dalam muatan permintaan. Dan bahkan jika penyerang tahu di mana harus meletakkan token CSRF dalam muatan, mereka harus membaca nilainya untuk meletakkannya di sana. Tetapi kebijakan lintas-asal browser mencegah pembacaan nilai cookie apa pun dari situs web target.
Logika yang sama tidak berlaku untuk cookie token auth, karena server mengharapkannya dalam header permintaan dan penyerang tidak harus melakukan sesuatu yang khusus untuk meletakkannya di sana.
sumber
src='bank.com/transfer?to=hacker&amount=1000
yang akan diminta browser, lengkap dengan cookie yang terkait untuk situs itu (bank.com
)?Tebakan terbaik saya untuk jawabannya: Pertimbangkan 3 opsi ini untuk cara mendapatkan token CSRF dari server ke browser.
Saya pikir yang pertama, permintaan body (sementara ditunjukkan oleh tutorial Express yang saya tautkan dalam pertanyaan ), tidak portabel untuk berbagai situasi; tidak semua orang menghasilkan setiap respons HTTP secara dinamis; di mana Anda akhirnya harus meletakkan token dalam respons yang dihasilkan mungkin sangat bervariasi (dalam input formulir tersembunyi; dalam sebuah fragmen kode JS atau variabel yang dapat diakses oleh kode JS lainnya; mungkin bahkan dalam URL meskipun itu tampaknya umumnya tempat yang buruk untuk menempatkan token CSRF). Jadi, meskipun dapat dikerjakan dengan beberapa penyesuaian, # 1 adalah tempat yang sulit untuk melakukan pendekatan satu ukuran untuk semua.
Yang kedua, tajuk khusus, menarik tetapi tidak benar-benar berfungsi, karena sementara JS bisa mendapatkan tajuk untuk XHR yang dipanggil, tajuk itu tidak bisa mendapatkan tajuk untuk halaman tempat diambilnya .
Yang meninggalkan yang ketiga, cookie yang dibawa oleh tajuk Set-Cookie, sebagai pendekatan yang mudah digunakan dalam semua situasi (server siapa pun akan dapat mengatur tajuk cookie per-permintaan, dan tidak peduli apa pun jenisnya). data ada di badan permintaan). Jadi terlepas dari kelemahannya, itu adalah metode termudah untuk diterapkan kerangka kerja secara luas.
sumber
Selain cookie sesi (yang merupakan standar), saya tidak ingin menggunakan cookie tambahan.
Saya menemukan solusi yang berfungsi untuk saya ketika membangun Aplikasi Web Halaman Tunggal (SPA), dengan banyak permintaan AJAX. Catatan: Saya menggunakan Java sisi server dan sisi klien JQuery, tetapi tidak ada hal ajaib jadi saya pikir prinsip ini dapat diimplementasikan dalam semua bahasa pemrograman populer.
Solusi saya tanpa cookie tambahan sederhana:
Sisi klien
Menyimpan token CSRF yang dikembalikan oleh server setelah login berhasil di variabel global (jika Anda ingin menggunakan penyimpanan web, bukan global itu baik-baik saja tentu saja). Instruksikan JQuery untuk menyediakan header X-CSRF-TOKEN di setiap panggilan AJAX.
Halaman "indeks" utama berisi potongan JavaScript ini:
Sisi server
Pada login sukses, buat token CSRF acak (dan cukup panjang), simpan ini di sesi sisi server dan kembalikan ke klien. Saring permintaan masuk (sensitif) tertentu dengan membandingkan nilai header X-CSRF-TOKEN dengan nilai yang disimpan dalam sesi: ini harus cocok.
Panggilan AJAX yang sensitif (data formulir POST dan DAPATKAN data JSON), dan filter sisi server yang menangkapnya, berada di bawah jalur / data layanan / *. Permintaan masuk tidak boleh mengenai filter, jadi ini ada di jalur lain. Permintaan untuk HTML, CSS, JS dan sumber daya gambar juga tidak ada di jalur / dataervice / *, sehingga tidak difilter. Ini tidak mengandung rahasia dan tidak dapat membahayakan, jadi ini baik-baik saja.
sumber