in Web Security

Membuat Web dengan Otentikasi berbasis Token

Pada artikel sebelumnya saya sudah menjelaskan cukup detil tentang cara kerja token yang dipakai pada internet banking. Artikel tersebut hanya menjelaskan sebatas teoretis saja, saya pikir akan lebih baik bila ada prakteknya. Oleh karena itu, seperti yang sudah saya janjikan, kali ini saya akan membuat sebuah contoh sederhana website dengan otentikasi yang menggunakan token seperti pada situs internet banking. Aplikasi token yang saya buat ini dikembangkan dari aplikasi yang bernama Mobile-OTP, dari aplikasi itu saya tambahkan beberapa fitur agar mirip dengan token yang dipakai di internet banking. Sedangkan aplikasi server/website saya harus membuat sendiri dari awal karena tidak tersedia di Internet.

Persiapan

Ada dua komponen yang terlibat dalam sistem ini, yaitu token yang dipakai oleh client dan tentu saja server. Token ada yang berwujud fisik seperti kalkulator kecil, ada juga yang berwujud software yang disebut juga virtual token. Sebenarnya token fisik maupun software sama saja, jadi dalam artikel ini saya akan membuat token yang berwujud software. Lebih spesifik lagi token ini dibuat dengan Java Mobile sehingga bisa diinstall di handphone yang mendukung Java. Jadi wujud fisik token yang berbentuk kalkulator bisa digantikan dengan wujud fisik sebuah handphone. Dalam artikel ini saya akan menggunakan emulator handphone yang dibundel dari Java Wireless Toolkit.

Komponen lainnya adalah server. Diperlukan web server dan database server, dalam artikel ini saya pakai XAMPP yang sudah dibundel dengan Apache, PHP dan MySQL.

Spesifikasi One Time Password di Aplikasi Contoh

Dalam aplikasi contoh ini, one time password didapatkan dengan mengambil 6 karakter pertama hasil penghitungan hash dengan fungsi MD5. Granularity sistem ini adalah 10 detik, dengan kata lain setiap 10 detik token akan menghasilkan OTP yang berbeda. Jika anda meminta token mengeluarkan OTP beberapa kali dalam rentang 10 detik, maka semuanya akan menghasilkan OTP yang sama. Kemudian baru ketika waktu masuk ke 10 detik berikutnya token akan menghasilkan OTP yang baru.

Dalam aplikasi contoh ini, umur OTP adalah 3 menit, artinya server harus menghitung semua OTP dalam time window 6 menit, yaitu 3 menit ke belakang dan 3 menit ke depan relatif terhadap waktu ketika server melakukan otentikasi. Konsekuensinya adalah setiap OTP yang dihasilkan token akan dianggap valid bila belum pernah dipakai dalam 3 menit sejak OTP dibangkitkan.

Spesifikasi Software Token

Token yang akan saya buat ini nantinya memiliki fitur yang sama dengan token internet banking pada umumnya. Pada kondisi normal nilai init-secret sudah ditanam di dalam token secara hardware, namun dalam token contoh ini tersedia fitur untuk melakukan inisialisasi nilai init-secret. Init-secret ini harus dicatat juga di server agar server bisa menghasilkan OTP yang sama dengan token.

Token bisa menghasilkan OTP dalam mode Challenge/Response maupun dalam mode Response Only (self generated). Challenge yang diterima oleh token adalah sepanjang 4 digit dan menghasilkan response sepanjang 6 digit hexadesimal.

Spesifikasi Website

Website dalam aplikasi contoh ini saya buat dengan PHP. Aplikasi ini terdiri dari 2 file saja, yaitu login.php dan transfer.php. Login.php digunakan untuk melakukan login dengan menggunakan response only pin dari token. Sedangkan transfer.php adalah untuk melakukan transfer uang dengan menggunakan challenge/response pin dari token.

Aplikasi ini saya pasang pada localhost yang terinstall Apache+MySQL+PHP dari XAMPP. Sebelum bisa melakukan transfer uang, user harus melakukan login di URL https://localhost/mytestbank/login.php . Perhatikan URL tersebut sengaja saya memakai https agar mirip dengan internet banking. Tentu saja browser anda akan berontak ketika menggunakan https karena memang saya tidak punya sertifikat yang ditandatangani CA untuk localhost. Bila anda kesulitan mengonfigurasi browser anda untuk memakai https tersebut, anda boleh memakai http biasa.

Pada saat login user diminta memasukkan username dan OTP yang dihasilkan dari token dalam mode response only (self generated). Bila login berhasil, maka user dialihkan ke halaman https://localhost/mytestbank/transfer.php . Berbeda dengan halaman login, pada saat transfer user diminta untuk memasukkan OTP dari token dalam mode challenge/response. Server memberikan challenge sepanjang 4 digit angka.

Aplikasi ini juga membutuhkan sebuah tabel MySQL bernama users yang saya masukkan dalam database bernama mytestbank. Tabel ini digunakan untuk menyimpan informasi pengguna website. Berikut adalah script SQL untuk membuat tabel users.

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(255) NOT NULL,
  `initsecret` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

Agar lebih mudah sebaiknya anda menginstall XAMPP atau WAMP dan menggunakan PhpMyAdmin untuk membuat tabel users tersebut.

Pembuatan Token

Token dibuat dengan Java Mobile (disebut midlet) yang sangat sederhana. Midlet ini hanya terdiri dari 2 file, yaitu MD5.java dan MobileOTP.java. Class MD5 adalah library untuk menghitung nilai hash MD5. Sedangkan class MobileOTP adalah class utama. Karena sourcenya cukup panjang, anda bisa mendownload sourcenya dalam file zip di sini. File zip itu bisa langsung anda extract ke dalam folder apps dalam Java Wireless Toolkit bila ingin menjalankan midlet itu dengan menggunakan emulator.

Saya akan menjelaskan fungsi utama dari token yaitu membangkitkan OTP dalam mode Challenge/Response dan mode Response Only. Perhatikan potongan kode token berikut yang berfungsi untuk membangkitkan OTP dalam mode Response Only.

now=new Date();										
epoch=""+(now.getTime()+((timez-12)*3600000));
epoch=epoch.substring(0,epoch.length()-4);
String otp=epoch+secret;
MD5 hash=new MD5(otp);
otp=hash.asHex().substring(0,6);

Kode di atas sangat sederhana, diawali dengan mengambil detik EPOCH sepanjang 9 digit (ini sama dengan EPOCH/10 karena granularitynya adalah 10 detik). Kemudian nilai EPOCH tersebut digabung dengan init-secret. String gabungan epoch dengan init secret ini dihitung hashnya dengan MD5. Kemudian 6 karakter pertama dari hash tersebut diambil sebagai OTP response only (self generated).

Kode berikut ini adalah untuk membangkitkan OTP dalam mode challenge/response. Kode tersebut sangat mirip dengan potongan kode di atas hanya perbedaannya adalah adanya challenge yang dalam kode tersebut ada pada variabel PIN. Gabungan dari epoch, init secret dan challenge dihitung nilai hashnya dengan MD5, baru kemudian diambil 6 karakter pertamanya sebagai OTP.

now=new Date();        				
epoch=""+(now.getTime()+((timez-12)*3600000));
epoch=epoch.substring(0,epoch.length()-4);        				
otp=epoch+secret+PIN;        				
hash=new MD5(otp);        				
otp=hash.asHex().substring(0,6);

Bila anda ingin mencobanya di hape anda, pastikan HP anda mendukung java. Anda bisa mengkopi file JAR aplikasi ini ke memory card anda dengan bluetooth/USB, atau anda bisa juga mendownload langsung dari browser hp anda. URL untuk mendownload file JAR midlet ini adalah http://www.ilmuhacking.com/wp-content/uploads/2009/07/MobileOTP.jar . Selanjutnya anda tinggal mengikuti petunjuk untuk instalasi aplikasi seperti biasa. Ingat sebelum dipakai diperlukan langkah inisialisasi nilai init-secret dengan cara mengetikkan #**# dalam field “CHAL”.

Berikut ini adalah screen capture dari aplikasi tersebut yang diinstall di HP saya. Dua gambar di bawah ini adalah prosedur inisialisasi init-secret ketika aplikasi pertama kali dijalankan. Nilai init secret ini harus dicatat dan disimpan ke dalam tabel user di server.

e90mobileotp1
e90mobileotp2

Gambar di bawah ini adalah screen shot ketika midlet token membangkitkan OTP dalam mode response only.

e90mobileotp5

Gambar di bawah ini adalah screen shot ketika midlet token membangkitkan OTP dalam mode challenge response.

e90mobileotp4

Pembuatan Aplikasi Web

Aplikasi web terdiri dari dua file yaitu login yang menggunakan OTP dalam mode response only, dan transfer yang menggunakan OTP dalam mode challenge response. Seperti halnya midlet token, aplikasi ini juga sangat sederhana. Fungsi utamanya adalah pada fungsi checkCR() dan checkRO() yang berfungsi untuk melakukan otentikasi dalam mode Challenge/Response atau Response Only. Berikut adalah isi dari fungsi checkCR dan checkRO.

// Check Challenge/Response Mode
function checkCR($chal,$otp,$initsecret)
{
 $maxperiod = 3*60; // in seconds = +/- 3 minutes
 $time=gmdate("U");
 for($i = $time - $maxperiod; $i <= $time + $maxperiod; $i++)
 {
    $md5 = substr(md5(substr($i,0,-1).$initsecret.$chal),0,6);
    if($otp == $md5) return(true);
 }
return(false);
}

// Check Response/Only Mode
function checkRO($otp,$initsecret)
{
 $maxperiod = 3*60; // in seconds = +/- 3 minutes
 $time=gmdate("U");
 for($i = $time - $maxperiod; $i <= $time + $maxperiod; $i++)
 {
    $md5 = substr(md5(substr($i,0,-1).$initsecret),0,6);
    if($otp == $md5) return(true);
 }
return(false);
}

Perbedaan kedua fungsi itu hanya pada adanya $chal pada fungsi checkCR() sedangkan pada fungsi checkRO() yang digabungkan hanya epoch dan initsecret. Mari kita ulas kedua fungsi tersebut karena inti dari aplikasi ini ada pada kedua fungsi itu.

Dalam artikel sebelumnya saya sudah menjelaskan mengenai time window atau toleransi yang diberikan server ketika melakukan otentikasi. Dalam contoh ini time window yang diberikan server adalah 3 menit ke depan dan 3 menit ke belakang relatif terhadap waktu ketika server melakukan otentikasi. Waktu (dalam detik EPOCH) ketika server melakukan otentikasi disimpan pada variabel $time (baris ke-5 dan baris ke-18), sehingga server harus menghitung semua otp dari $time-180 hingga $time+180 (3 menit ke belakang dan 3 menit ke depan) pada baris ke-6 dan baris-19.

Selanjutnya pada barus ke-8 dan baris ke-21 server menghitung otp dengan mengambil 6 karakter awal dari fungsi hash gabungan dari epoch+initsecret dan challenge (khusus untuk checkCR).

Di bawah ini adalah source untuk file login.php. Untuk melakukan otentikasi, login.php memanggil fungsi checkRO() pada baris ke-12. Namun untuk memanggil fungsi checkRO() dibutuhkan init secret dari user yang disimpan dalam tabel users sehingga server harus melakukan query ke tabel users (baris ke-8). Selanjutnya bila otentikasi berhasil server akan menyimpan username dan initsecret pada session kemudian mengalihkan user ke aplikasi transfer (transfer.php).




Login Internet Banking MyTestBank

$err"; ?>
Username
Token PIN:

Di bawah ini adalah source untuk file transfer.php. Untuk melakukan otentikasi server memanggil fungsi checkCR() pada baris ke-13. Fungsi checkCR ini membutuhkan init secret, challenge yang diambil dari session. Kemudian server akan memberikan pesan "Transfer Success" atau "Wrong PIN" tergantung dari hasil fungsi checkCR().

Pada baris ke-21 dan ke-22 server membangkitkan nilai acak sepanjang 4 digit sebagai challenge. Challenge ini disimpan dalam session agar tidak bisa dimanipulasi user. Bila challenge disimpan sebagai hidden field dalam form, maka user bisa bebas mengubah isi challenge itu.

Transfer Success";
	} else {
		$msg = "Wrong PIN";
	}
} 
srand(time());
$challenge = sprintf("%04d",(rand()%9999));
$_SESSION["challenge"] = $challenge;

?>


$msg"; ?>

Transfer Form

No Rekening Tujuan:
Jumlah: Rp.
Challenge Code: (Masukkan kode ini ke dalam token anda)
Token PIN : (Masukkan response dari token anda)

Anda bisa mendownload semua source php di sini.

Test

Sebelum mencoba pertama saya harus menyamakan jam di token (handphone) dengan jam di server. Setelah sama baru kita uji coba aplikasi ini dengan skenario berikut:

Nasabah myTestBank ingin memakai aplikasi internet banking myTestBank untuk mentransfer sejumlah uang. Untuk itu dia baru saja mendownload Midlet Token dan menginstallnya ke HPnya. Token midlet tersebut diinisialisasi dengan nilai init secret 369e4a62be0e579a. Setelah mendaftar user tersebut mendapat username rizki. Untuk menggunakan fasilitas ini dia harus membuka browser ke URL https://localhost/mytestbank/login.php .

Selain menyamakan jam di token dan di server, init secret di token dan di server harus sama. Gambar di bawah ini menunjukkan bahwa init secret di hape saya sudah sama dengan yang di tabel users MySQL.

initsecret-server-token

Kini user sudah siap mencoba untuk login ke aplikasi MyTestBank di URL https://localhost/mytestbank/login.php . Berikut ini adalah screen capture ketika user login.

loginotp

Setelah login berhasil, kemudian user dihadapkan pada form untuk melakukan transfer uang. Berikut ini adalah screen shot pada browser dan hp user ketika user melakukan transfer.

transferformOTP

Setelah memasukkan OTP dengan benar, server memberikan informasi "Transfer Success". Kini user telah berhasil melakukan transfer. Berikut adalah screenshot ketika transfer berhasil dilakukan.

transfersuccess

Write a Comment

Comment

38 Comments

  1. kewl man, detail banget.
    The question is, apakah bisa dibuat kloning key token yang sudah ada? *evil mode:ON*

  2. salam kenal dari ilham pada mas rizki. saya mohon bantuan dari mas rizki. dulu saya membuat sebuah webblog, dan sekarang saya lupa username dan passwordnya.sudah dua bulan saya berusaha mendapatkan username dan passwordnya tapi masih belum berhasil.saya sudah menggunakan emailspider,emailadreesfinder,dll tapi tetap nihil.saya harap mas rizki bisa membantu masalah saya. terimakasih mas rizki.

  3. Congrats!!
    dari Token sampe internetBanknya… lengkap deh!
    Xampp nya versi Linux atau Win? atau sama aja hasilnya?
    truz, HP nya pake symbian versi berapa? yg support java? bisa pake Soner G502 gak? Regards

  4. mas contoh bikin databsenya diperjelas dong mas,..
    klo ga ada file nya sendiri ga,..
    hmm,..
    makasih sebelumnya mas,..
    assalam,.

  5. menarik sekali 🙂
    cuman kepikir kalo login hanya dg username + tokenpin yg dihasilkan dari response only mode apa tidak riskan?? begitu token jatuh ke tangan orang lain dan username diketahui .. maka bisa disalahgunakan.

    Gimana kalo login itu username + token pin yg dihasilkan dari Challenge/Response mode. Challenge code yg dimasukkan adalah password user yg hanya diketahui oleh user. Jadi di database ada satu kolom lagi yaitu ‘loginpassord’ yg dipakai sebagai challenge code untuk mendapat token pin.

  6. @tedi
    iya memang riskan, karena ini hanya contoh penggunaan R/O token. praktek dalam internet banking yang selama ini dipakai sudah baik, login seperti biasa dengan username dan password, kemudian baru pakai token pin untuk transaksi.

    solusi yang mas tedi sampaikan dengan menyimpan login password di database juga riskan, karena itu berarti password harus disimpan dalam bentuk plaintext bukan hash.

  7. perkenalkan namaku detopa saga dan salam kenal………
    ooyaa.aku boleh tahu gak?…..arti dari ngehacking itu apa,an…. ya???????????…..soalnya aku masih kurang paham nich kalau soal ngehacking…
    tolong dong kasih pengertian ke saya lewat alamat emailku ini di:[email protected]
    udah gitu aja yang jadi pertanyaanku….

  8. Mas Rizky, saya sudah baca artike tentang Token ini dan isi’a bagus sekali.

    Saya mencoba untuk menjalankan source code Token’a menggunakan Netbeans tapi setelah saya run terjadi error seperti ini :

    *** Error ***
    A problem occured during deploying application from http://127.0.0.1:5371/MobileOTP.jad
    Reason:
    Corrupt JAR, error while reading: MobileOTP.class
    C:\Users\Luthfan\Documents\NetBeansProjects\MobileOTP\nbproject\build-impl.xml:889: Execution failed with error code 1.
    BUILD FAILED (total time: 32 seconds)

    Mohon pencerahan’a ya mas Rizky,
    karena kadang saya juga menemui error seperti ini di aplikasi J2ME yang lain.

  9. Saya sudah dapet pencerahan’a mas Rizky,
    Saya coba merubah bagian “import MobileOTP.MD5;” menjadi “import MobileOTP.MD5.*;”
    Dan ternyata berhasil.

    Terima kasih banyak mas Rizky.

  10. mas rizky….

    artikelnya bagus banget apalagi tentang internet security.

    membaca responnya mas tedi ada benernya juga, akan riskan bila mekanisme yang digunakan adalah Response Only. Tapi menurut mas Rizki bila solusinya dengan C/R tetap riskan pada databasenya, tolong dijelaskan?

    Oiya mas, kira2 ada pengembangannya dari aplikasi web otentikasi dengan token tersebut, siapa tahu bila ada pengembangan, bisa saya jadikan masukan untuk Penelitian saya, terima kasih mas.

    Salam

  11. mas, cara nyamain ato cara ngliat sama tidak nya init-secret antara di mobile-OTP sama di web nya gmn?
    trus yg di database nilai initsecret nya itu dimasukin manual t?????
    makasi man

    • Pertama thanks 4 mas risky yg udh buat tutorial tentang internet security “token” ,,,

      numpang jawab ya mas…,,,

      1. Pada sisi MobileOTP modifikasi script sedikit :

      if ( c == infoCommand ){
      now=new Date();
      epoch=””+(now.getTime()+((timez-12)*3600000));
      epoch=epoch.substring(0,epoch.length()-4);
      Canvas infoc = new Canvas(){
      public void paint(Graphics g){
      int w=getWidth();
      int h=getHeight();
      g.setColor(255,255,255);
      g.fillRect(0,0,w,h);
      g.setColor(0,0,0);
      g.drawString(“Epoch-Time : “,1,1,0);
      g.drawString(epoch,1,1+h/7,0);
      g.drawString(“Initialization : “,1,1+2*h/7,0);
      g.drawString(initdate,1,1+3*h/7,0);
      //Dibawah script untuk menampilkan initsecret
      g.drawString(“Initsecret : “,1,1+4*h/7,0);
      g.drawString(initsecret,1,1+5*h/7,0);
      }
      };
      infoc.addCommand(backCommand);
      infoc.setCommandListener(this);
      Display.getDisplay(this).setCurrent(infoc);
      }

      2. Pada sisi PHP buat cript initsecret.php

      3. Yg di database nilai usename dan initsecretnya di inputin manual mas surya.

      Semoga bermanfaat.

        • include(“initdb.php”);

          //Perhatikan username harus ada pada table users
          $sql = “select secretcode from users where username=’zhemora’ “;
          $res=mysql_query($sql);
          $arr_row=mysql_fetch_array($res);
          $secretcode = $arr_row[0];
          print “Initsecret = $secretcode”;

  12. mas, aku udah yoba simulasi nya..
    peratama login php ya, ketika aku masukan challange dari token berhasil dan diarahkan ke transfer php ya.

    challenge ya muncul, dan nilai challange tersebut gw input ketoken dan tokenya ngerespon dengan password

    namun pas, aku masukkin nilai yang dihasilkan token ke web transfer,
    salah terus mas..???

    masalahya kira-kira pa ya mas??
    thanks y mas???

  13. mas rizki..
    saya sudah bisa running MobileOTP nya..
    tp kok initsecret’y gak ter-initialize di MobileOTP ya..??

    pada saat loading login.php,, input Pass ke Token Pin kok masih salah ya..??
    & saya juga udah coba edit source code’y mengikuti code pada share comment rekan2 diatas juga masih muncul WRONG Pin..

    tolong pencerahan’y..
    Makasiiiih.. 🙂

  14. mas sy ini awam bgt ttg token2x,, nah yang ungin sy tanyakan perbedaan TOKEN sama TOKET itu ap y..?? trima kasih pencerahannya.

  15. terimakasih mas sangat membantu sekali dalam pengerjaan TA saya.
    oh ya saya mau nanya kalo dibuat dengan hash SHA1 gimana ya mas?,apa lebih bagus atau tidak

  16. mas thanks banget buat artikelnya,,, dan ini sangat bagus sekali…

    saya mohon pencerahannya ,, masalahnya sama seperti mas Andy dan Queenshe,, ketika login selalu salah pin padahal step by step sudah dijalankan dengan benar…

    mohon arahanya… thanks 🙂

  17. menarik juga ya OTP ini, saya dah coba, tp kok yg mnurut ane gak secure dr initsecret yg di database user,kok masih berbentuk plainteks ya?

    perlukah initsecret di enkrip untuk menjaga kerahasiaan initsecret?

  18. mas riski, transfer dah success tp kok muncul notif begini ya..

    Notice: Undefined index: username in C:\xampp\htdocs\mytestbank\transfer.php on line 9
    Transfer Success

  19. misi mas saya juga sedang menggarap aplikasi ini
    kalau token yang saya buat melalui exe dari vb or java syncronize waktunya gimana ya

    • kalau programnya jalan di PC (exe windows), waktunya adalah jam PC. kalau jalan di mobile phone, waktunya adalah jam di handphone. disamakan saja waktunya, di client dan di server.

      • mas rizki, kenapa ya hasil inisialisasi awal saat kita #**# kenapa nilainya sama semua ya, FYI saya udah coba di 3 hanphone yg berbeda tp hasil dari inisialisasi initsecretnya selalu sama
        eef87e2faba9e4bc
        kenapa ya?

  20. Menarik sekali …Tapi yang saya bingung …spt token BCA, mandiri , dll…kan hasilnya berupa desimal…….misal: 563727
    Sedangkan diatas… hasilnya berupa heximal… gimana tu??

    Terus…mungkin gak… dari nilai token yg ada..kita bisa tau initsecretnya ???

    Please email sy ya…utk kajian ilmiah saya

Webmentions

  • Memahami Cara Kerja Token Internet Banking « Nd4s4ch's Zee Blog January 6, 2016

    […] repost from master hack […]