Lembur Memperbaiki Celah Keamanan CSRF

[Cross Site Request Forgery](http://en.wikipedia.org/wiki/Cross-site_request_forgery) atau CSRF (dilafalkan ‘sea-surf’) adalah sebuah celah keamanan dimana aplikasi web terlalu mempercayai sebuah *request* walaupun *request* tersebut bukan berasal dari inisiatif pengguna. Celah keamanan ini belakangan menjadi populer akibat [bobolnya daftar kontak](http://www.oreillynet.com/xml/blog/2007/01/gmail_exploit_contact_list_hij.html) pada layanan email [Gmail](http://gmail.com).

Kalau ada yang heran mengapa blog ini tidak diperbaharui sejak kurang lebih satu setengah bulan yang lalu, itu karena saya terpaksa lembur memperbaiki berbagai macam aplikasi yang pernah saya buat sejak bertahun-tahun yang lalu. Ternyata sebagian besar aplikasi yang pernah saya buat memiliki celah keamanan CSRF ini :(.

**Penjelasan**

Celah keamanan CSRF ternyata juga menjangkiti [WordPress](http://wordpress.org) jaman *baheula* yang memotori blog ini. Saya tidak tahu apakah di versi terbaru hal ini sudah diperbaiki. Tetapi untuk memudahkan menjelaskan tentang celah keamanan CSRF ini, mari kita gunakan contoh blog saya ini.

Salah satu fungsi dari panel administrasi WordPress adalah menghapus tulisan. Sebagai contoh, ketika saya membuka menu ‘Posts’, saya disuguhkan fungsi ‘Delete’. Jika saya klik maka akan tampil konfirmasi, dan jika saya iyakan, maka saya akan dibawa ke URL semisal `https://priyadi.net/wp-admin/post.php?action=delete&post=1`. URL tersebut akan menghapus *posting* pertama dari blog ini. (sebenarnya*posting* pertama tersebut yang dibuat saat instalasi WordPress sudah saya hapus sejak dulu)

Karena semua orang dapat memiliki blog berbasis WordPress dan mengetahui URL dasar dari blog ini, maka semua orang bisa mengetahui URL untuk menghapus tulisan tersebut. Hanya saja, untuk dapat benar-benar menghapus sebuah tulisan di blog saya, yang mengakses URL tersebut harus melakukan login terlebih dahulu, atau dengan kata lain saya sendiri.

Sekarang yang menjadi masalah hanyalah bagaimana membuat saya mengakses URL tersebut tanpa saya sadari. Ternyata bukanlah hal yang terlalu sulit, cukup buat sebuah halaman web dengan isi sebagai berikut:



Dan suruh saya untuk mengaksesnya. Jika berhasil, saya akan mendapatkan sebuah halaman web yang berisi ‘gambar rusak’. Dan saya tidak akan menyadari jika saya baru saja menghapus tulisan pertama saya kecuali jika saya melihat kode sumber dari halaman tersebut. Dan walaupun saya mengetahuinya, hal tersebut sudah terlambat.

Selain metoda di atas, ada banyak metoda lain untuk melakukannya, termasuk juga untuk *request* POST dan untuk menghilangkan ‘gambar rusak’ tersebut.

Kalau saya perhatikan, celah CSRF ini baru populer akhir-akhir ini. Dan dengan demikian sangat banyak contoh kode pemrograman baik di Internet dan di buku-buku memiliki celah keamanan ini.

**Solusi untuk pengakses**

Celah keamanan ini terletak di sisi aplikasi yang berjalan di *server*. Dan dengan demikian tidak dapat sepenuhnya ditanggulangi di sisi *client*. Walaupun demikian, ada baiknya pengguna meminimalkan dampak akibat celah keamanan ini. Cara-cara praktis yang menurut saya dapat sedikit banyak mencegah dampak dari celah keamanan ini adalah sebagai berikut:

* Jangan lupa melakukan *log out* setelah usai menggunakan layanan di Internet.
* Gunakan perambah (*browser*) yang berbeda untuk mengakses layanan yang anda percayai (web mail dan semacamnya) dan untuk keperluan menjelajah Internet.
* Mematikan fungsi *third party cookies*. (sebenarnya saya tidak tahu persis apakah ini akan berfungsi atau tidak)

**Solusi untuk pembuat program di sisi server**

Banyak pihak yang menyarankan untuk membatasi masa berlaku *cookie* sampai misalnya 5 atau 10 menit. Solusi yang mudah, tetapi juga sangat mengganggu dan tidak sepenuhnya menutup celah keamanan ini.

Satu-satunya cara yang efektif adalah membuat URL untuk melakukan fungsi penting sulit ditebak oleh orang lain. Sebagai contoh URL untuk menghapus tulisan di blog ini di atas dapat dimodifikasi menjadi misalnya `https://priyadi.net/wp-admin/post.php?action=delete&post=1&x=15eb0de86bb6edff65bb3c3786c21b08824eb5ed`.

Variabel ‘x’ tersebut adalah hasil fungsi [SHA1](http://en.wikipedia.org/wiki/SHA_hash_functions) dengan ‘adonan’ berupa nomor tulisan (variabel ‘post’) dan sebuah variabel rahasia yang hanya diketahui oleh aplikasi di *server* tersebut. Jika variabel ‘x’ tersebut tidak ada atau berbeda daripada yang seharusnya, maka aplikasi akan menolak untuk melakukan penghapusan. Karena orang lain tidak mengetahui isi variabel rahasia tersebut, maka ia tidak dapat dengan mudah menebak URL tersebut.

Solusi lain yang bersifat ‘sapu jagat’ adalah dengan menggunakan [*wildcard hostname*](http://en.wikipedia.org/wiki/Wildcard_DNS_record). *Wildcard hostname* memungkinkan kita membuat sembarang hostname yang merujuk ke IP yang sama. Sebagai contoh, URL tersebut di atas dapat kita modifikasi menjadi misalnya `http://h437429741748977.priyadi.net/wp-admin/post.php?action=delete&post=1`. Di sini ‘h437429741748977’ merupakan nomor acak yang dibuat pada saat pengguna melakukan *login*. Karena nomor tersebut acak dan *cookie* kita buat hanya berlaku pada domain acak tersebut, maka orang lain akan kesulitan untuk menebak URL yang tepat.

Tetapi cara yang paling tepat untuk membuat URL sulit untuk ditebak tentunya tergantung dari masing-masing aplikasi.

\*\*\*

Akhir kata, saya ucapkan selamat berlembur…

145 comments

  1. mungkin bisa juga dengan menggunakan halaman konfirmasi dengan dengan variable yang dilewatkan melalui metode HTTP POST

  2. OK, itu menjawab pertanyaanku kemarin ketika baru sadar (ups!) blogmu terbengkalai sejak Januari. Kupikir pasti ada yang penting banget sampai absen segitu lamanya.

  3. yoi bro.. bugs spt ini sering saya gunakan untuk posting di beberapa forum yang sudah dilock. dan masalah spt ini sudah saya sadari dari sejak lama, hanya saja saya kurang begitu piawai menanganinya :)

  4. hmm, kalo ngga salah waktu itu google kesalahanya ada di javascriptnya ya, tapi itukan dah lama, ternyata ini toh, infor lengkapnya lagi ada nda ???

  5. \:d/ hehehe, ketahuan deh, saya dulu pertengahan 2004 juga sering pakai metode ini buat ngisengin orang, kok baru sekarang dibahas yaks :)>-

  6. hoho.. itu toh yg namanya CSRF.. :D

    saya pernah berpikiran untuk “mengacak” variabel yang disertakan dalam get supaya sulit ditebak alamat URL-nya.. :D

    ternyata ini baru marak, yak.. :)

  7. #21 : wordpress 2.1.1 blum aman, makanya ada updatenya di 2.1.2.

    Om pri, bendera singaporenya koq sama dengan Indonesia gitu??? :)>-

  8. Hmm…
    Kirain habis kirim tulisan tentang statemen RS kemarin Om Pri ‘diculik’ aparat dan ‘diamankan’ :d

    Hehehe….

  9. kalo contohnya wordpress, kayaknya udah tau semua dah. bukannya itu sederhana. Saya dulu bandinginnya dengan CMS JOOMLA.

    Joomla dan virtuemart saking rumitnya address URL – nya bingung untuk nyiasatin SEO. Ternyata kerumitan mengandung hikmah buat Joomla.

    Selamat datang di republik Joomla

  10. ouwww..ternyata itu toh penyebab om pri menghilang….
    waduh bahaya juga yah kalo ternyata ada celah kayak gitu, bisa2 blog kita ilang ga ada isinya di obok2 orang iseng :(

  11. sudah dilembur saja perlu waktu lebih dari sebulan, gimana kalau santai gemulai? *ngebayangin jumlah aplikasi yang dilemburin :)

  12. untuk aplikasi2 bisnis jangan sekali2 bikin spt ini:

    post.php?action=delete&post=1

    tapi bikin spt ini:

    post.php?action=asdf2wras459asfaskfa0oralasdf

    lebih susah di tebak. Saya paling suka ngacak2 url di browser salah satunya ini (punya perusahaan media besar):

    index.php?fuseaction=home.detail&id=11&section=94

    saat diganti dgn id=11′ ouchhh… mengerikan

  13. Kelamaan, Pak. Terakhir nge-check masih yg ‘Kesalahan Presisi’ terus. Kangen benget soalnya –sama tulisannya– ….:”>

  14. Mohon maaf Pak, ini ada pertanyaan beda topik. Sebelumnya sudah coba send email, tapi saya belum bisa pakai wizard. Saya awam sekali, pak, maaf. Begini pak, saya salah satu penggemar blog bapak. Selain membaca blog bapak, terkadang saya juga membaca blog yg ada friend list bapak (link ya namanya?) unt memudahkan saya memcari referensi blog yg isinya informatif. Sayangnya, ketika saya hendak membaca blog teman2 Bapak, kok link-nya jadi ga ada ya? Yang saya ingin tau, link tersebut tidak ada sementara karena ada perbaikan sehubungan dgn posting-an terakhir atau memang ditiadakan selamanya, pak?
    Terima kasih unt jawabannya :)

  15. aduh om pri lama ga keliatan euy… ternyata lembur.. :D. saya juga sering menemukan masalah yang sama, tapi saya lebih sering cuek… :”>

  16. wah seharusnya diganti tuh

    Priyadi Iman Nurcahyo, an ordinary human being living in Australia

    hehehehe:d

  17. tanya pri,

    celah keamanan CSRF ini di wordpress emang bisa dimanfaatkan oleh pengunjung/komentator?

    setau gue kalo kita strict di form komentar dengan membatasi tag html tertentu, maka kita gak terlalu kerepotan, kecuali kalo pengunjung/komentator punya akses untuk ngedit tag html. CMIIW

  18. IMO, CSRF ini termasuk kesalahan sepele yg sering dianggap remeh oleh developer/programmer, tapi bisa berdampak gawat. Mirip seperti sql injection. Krn merupakan kesalahan sepele, sebenarnya untuk mencegahnya juga gak terlalu sulit. Kalo yg saya terapkan selama ini mirip seperti solusi yg disampaikan bung Priyadi ttg penambahan variabel request, cuman sedikit lebih enhanced. ;)

  19. Tapi tetep saja, masa2 kritis adalah antara user logout hingga request time out. Mungkin hanya 3-5 menit waktunya. Tapi kalo ini bisa dimanfaatkan, maka rasanya gak ada solusi yg mudah untuk mencegah hal tsb, tanpa mengorbankan kenyamanan user. :( Intinya, pembiasaan logout pada user itu adalah harus, walaupun meninggalkan komputer hanya 1-2 menit.

  20. #53: makanya, solusi paling gampang yaitu pake dua browser. satu untuk keperluan penting, yang satu lagi untuk keperluan browsing casual.

    membatasi waktu login cuma akan memperkecil window, tapi tidak menghilangkan resiko. dan masih ditambah berkurangnya kenyamanan :).

  21. Mas Pri, komentar #55 .. dengan catatan pemilik situs sudah login, atau belum? apakah maksudnya autentifikasi pemilik situs dimanfaatkan untuk menjalankan script tsb ya?

  22. Ma’af, salah ketik. Yg saya maksud masa kritis pada posting #53 adalah dari user idle hingga time out.

    #56:
    Solusi tsb kan di sisi client, dan juga gak bisa menjamin keamanan pada masa kritis krn sangat tergantung pada kebiasaan dan kebisaan user. Krn itu, dalam kondisi tertentu dimana kenyamanan harus mengalah pada faktor keamanan, maka saya biasanya menerapkan entri ulang password user (yg sedang login) pada setiap operasi yg sangat beresiko. Untuk keamanan yg benar2 sangat beresiko, saya menerapkan mekanisme approval oleh user lain (yg levelnya lebih tinggi).

  23. #59: oh, maksudnya di sisi server. kalau di sisi server, pakai salah satu dari kedua cara saya di atas sudah pasti tidak akan bisa dibobol pakai CSRF, walaupun sesi user tidak dibatasi waktunya sekalipun.

    #58: tentunya si yang punya web site sudah harus login dulu. tapi di wordpress kan cukup login sekali untuk seumur hidup hehehe :).

  24. #61:
    Betul, developer bisa menjamin keamanan di sisi server. Tapi kontrol developer di sisi client (browser) agak terbatas. Inilah sumber masalah yg sulit dipecahkan di aplikasi web. Developer bisa memaksimalkan security di sisi server tapi seringkali yg bocor di sisi client, entah krn hole di browser atau perilaku user yg kurang hati2. Point pertama solusi untuk pengakses itu salah satu yg seringkali dilupakan user. :) Berbeda dgn aplikasi desktop dimana perilaku aplikasi client bisa dikontrol sepenuhnya oleh developer. Itu mungkin sebabnya aplikasi2 perbankan yg melibatkan proses2 yg beresiko tinggi tetap dibuat sbg aplikasi desktop, atau setidaknya berupa applet. ;)

  25. walaaaaaah,
    browser saya 3rd party Firefox 2.0 (BonEcho/2.0 (stipe))
    it’s ok lah dibilang unbranded. yang penting stipe kereeeen :D

    tp saya merambah (browsng) dr Padang kok, bukan dr Aussie, pk TelkomSlowdy.

    Nah, Mas Pri, bs gak bikin penjelasan knp koneksi SPEEDY ini dianggap dr OSTRALI.

  26. wah blog ini beneran seleb blog de :d… sekian lama ga diupdate… sekalinya diupdate… eh sehari udah lebih dari 70 komentar…
    selamat ngeblog lagi ya mas…

  27. fuhh..!! :-? kirain si Om jadi korban banjir..
    lama nunggu isi blog yang baru.. eh, gak taunya postingan yang bener2 gak ngerti kamsudnya.. :(( *maklum anak IPS dulunya *:d

  28. Pak pri, sudah 43 hari aku menantimu, dikira udah mau pensiun (seperti april mop-mu itu),ternyata tidak!
    pak pri comes again. meskipun aku nggak ngerti apa itu CSRF (se-sarf)

  29. Salam kenal Pri.
    #61

    tentunya si yang punya web site sudah harus login dulu. tapi di wordpress kan cukup login sekali untuk seumur hidup hehehe

    Pilihan untuk “Remember Me” saat login, salah satu yang tidak pernah saya aktifkan meskipun akses pake komputer sendiri.

  30. Mas, mungkin lebih enak bikin sendiri softwarenya. Ya, meski tetap akan ada celahnya, minimal agak beda konsepnya dengan yang ada. misal pakai wordpress. Jadi harus mempelajari konsepnya.

  31. waduh
    aku ketinggalan brita…. lupa ga ngeliat feeds borkmark
    diposting tgl 9 Maret ya?
    :d
    sekalian ngetes gravatar aahhh…

  32. Pak Priyadi, tanya nih. Bila demikian, setelah post #1 terhapus, lalu dilakukan lagi prosesnya, berarti #2 -> #1 dan kehapus lagi ya? Jadi lama2 abis gitu semua post?

    Masih belum mudeng nih.

  33. om pri… memang selebriti ya.. buuanyak banget penggemarnya… salam kenal dari masprim..eh .jangan salah nama ya.. aku masprim dari Pekanbaru :)

  34. hehehe bisa dipake buat ngisengin orang di frenster lho :P. bisa bikin orang gak nyadar ngapus temen2nya dia :D.

  35. Wah, ternyata ada kelemahan juga ya? tapi spertinya ga semua orang mau bersusah2 begitu kok, kecuali iseng… Tapi maturnuwun mas Pri atas bagi2 ilmunya…:D

  36. Waduh Kalau lemburnya sampai sebulan gini bisa bangkrut nih kantornya. untung kantor milik sendiri ….. :d

  37. Huhehehe … rame bener komentarnya.

    Saya kira kalau aplikasi yang pakai session juga kena mas Pri. Huahaha, saya nggak jadi lembur deh nih kayaknya.

    Paling nggak, di dalam aplikasi juga diterapken kalau mo delete jangan pake QueryString kekeke. Pake metoda POST aja terus di tambah pertanyaan dalam sebuah FORM, beneran mo delete nggak? :D.

    Itulah intinya sekarang saya masih ragu menerapkan AJAX dalam server produksi. Huancur nggak karuan deh kalau datanya sensitif.

  38. Pri, Februari kemarin aku coba kasih comment, malah error yang muncul. Bla-bla-bla MySQL apa itu gitu. Sampai kelihatan full path-nya segala (hmm pakai shared hosting ya?). Apa itu juga gara-gara si sea-surf?

  39. :-? menurut om oy uyo…ada 2 jenis hacker….yg jago dan yg sabar..nah menurut om itu lg..yg mendeface web presiden itu adalah hacker yang sabar…gmn om pri?
    komen dong…tentang ini…

  40. Kenapa alamat yang berada dalam tag code tidak di linebreak aja Pak? kan merusak estetika blog sampeyan? lagipula toh meski di break kan tidak mengubah arti dari apa yang sampeyan maksudkan.

    (bukan bermaksud menggurui master seperti anda, cuman penasaran sama alasan anda dibalik itu. Siapa tahu alasannya cukup masuk akal untuk diikuti oleh blogger baru seperti saya)

  41. Wah bang Pri aku pake WP versi 2.03 , aman ora !?:-? wah keren banget ya bang Pri sekalinya nulis artikel langsung dibanjiri komentar:o. Eh Lemburnya dapat duid ndak bang Pri :-“

  42. makasih tips nya om. mudah dimengerti. sering2 bikin tutorial security semacam ini yak :)

  43. hehehhe, kalau yang begini perlu disiplin tinggi dalam pengembangan aplikasi, keculai klo frameworknya sudah support pengamanan secara built-in utk CSRF.

    Lembur gk ya? .. *dag dig dug*

Leave a Reply to Koen Cancel reply

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