Agu 27 2012

WP-reCAPTCHA

Hari ini saya mengganti plugin captcha yg digunakan pada blog ini. Ini saya lakukan, karena proteksi yg diberikan oleh plugin sebelumnya sepertinya kecolongan. Banyak spam yg masuk, dan feeling saya itu bukan dilakukan oleh manusia, melainkan bot. Ya, mungkin saja Optical Character Recognition (OCR) yg digunakan sudah cukup canggih :D

Adapun plugin penggantinya adalah seperti yg tertera di judul postingan ini, yaitu WP-reCAPTCHA. Mudah-mudahan dengan plugin ini, barisan pertahanan blog saya lebih kuat dalam membendung serangan spam.

  • Facebook
  • Twitter
  • Google Plus
  • LinkedIn
  • RSS
  • Print

Permanent link to this article: http://www.muhammadalvin.net/2012/08/wp-recaptcha/

Jan 17 2012

Pengurutan (Sorting) Multi Kolom dengan Java

Pengurutan merupakan sesuatu yang umum dan sering diperlukan. Saat belajar algoritma dan pemrograman, topik pengurutan biasanya selalu ada. Masalah pengurutan ini juga sering muncul dalam programming, baik itu dalam programming ilmu komputer (seperti soal-soal ICPC, TopCoder, dll) maupun dalam programming dunia industri.

Andaikan kita seorang software developer yang sedang mengerjakan proyek web sepak bola. Dalam web tersebut, kita akan menampilkan klasmen suatu liga. Nah, buat yang belum mengerti apa itu klasmen, begini penjelasannya.

Klasmen merupakan tabel berisi data hasil pertandingan. Hasil pertandingan yang dimaksud adalah:

  • jumlah pertandingan yang sudah dijalani (Wins + Draws + Loses [lihat 3 item selanjutnya!])
  • jumlah pertandingan yang berakhir dengan dimenangkan (Wins, disingkat menjadi W)
  • jumlah pertandingan yang berakhir seri (Draws, disingkat menjadi D)
  • jumlah pertandingan yang berakhir dengan kekalahan (Loses, disingkat menjadi L)
  • jumlah gol ke gawang lawan (Goals For, disingkat menjadi GF)
  • jumlah gol ke gawang sendiri (Goals Against, disingkat menjadi GA)
  • selisih gol (Goals Difference, disingkat menjadi GD, yaitu GF – GA)
  • poin (Points, disingkat menjadi Pts, yaitu 3 * W + D)

Klasmen disusun berdasarkan poin. Tim yang memiliki poin lebih besar akan berada di atas, demikian sebaliknya. Jika poin kedua sama, diurutkan berdasarkan selisih gol. Tim yang memiliki selisih gol lebih besar akan berada di atas, demikian sebaliknya.

Perhatikan data hasil pertandingan (pertengahan Januari 2012) dari enam klub English Premier League berikut:

Klub/Tim             Wins  Draws  Loses  Goals-For  Goals-Against
-----------------------------------------------------------------
Arsenal              11    3      6      36         28
Chelsea              12    4      5      40         25
Liverpool            9     8      4      24         18
Manchester City      15    3      2      56         16
Manchester United    15    3      3      52         20
Tottenham Hotspur    14    4      3      39         21

Tabel di atas masih berisi data mentah dan belum diurutkan (urutan sementara berdasarkan nama klub). Untuk mengurutkannya, kita harus menghitung poin dan selisih goal, sebagai berikut:

Klub                 W   D  L  GF  GA  Pts(1)  GD(2)
----------------------------------------------------
Arsenal              11  3  6  36  28  36      8
Chelsea              12  4  5  40  25  40      15
Liverpool            9   8  4  24  18  35      6
Manchester City      15  3  2  56  16  48      40
Manchester United    15  3  3  52  20  48      32
Tottenham Hotspur    14  4  3  39  21  46      18

Keterangan
(1) Pts = points = poin
(2) GD = goals difference = selisih gol

Maka klasmen akan diperoleh sebagai berikut:

Klub                 W   D  L  GF  GA  Pts  GD
----------------------------------------------
Manchester City      15  3  2  56  16  48   40
Manchester United    15  3  3  52  20  48   32
Tottenham Hotspur    14  4  3  39  21  46   18
Chelsea              12  4  5  40  25  40   15
Arsenal              11  3  6  36  28  36   8
Liverpool            9   8  4  24  18  35   6

Perhatikan bahwa data sekarang telah diurut berdasarkan poin (Pts) dan selisih gol (GD). Ada dua klub yang memiliki poin sama, yaitu Manchester City dan Manchester United. Tetapi, karena selisih gol Manchester City lebih besar, klub tersebut berada di atas.

Sekarang, anggap data hasil pertandingan tersebut disimpan di tabel tbl_klasmen dalam database. Tabel tersebut memiliki struktur seperti ini:

Field            Type
------------------------
team_name        VARCHAR
wins             INTEGER
draws            INTEGER
loses            INTEGER
goals_for        INTEGER
goals_against    INTEGER

Dan berisi enam data seperti yang diperlihatkan pada tabel pertama di atas.

Jika menggunakan query SQL, maka untuk mendapatkan klasmen akan semudah ini:

SELECT *, (3 * wins + draws) AS points, (goals_for - goals_against) AS goals_difference
  FROM `tbl_klasmen`
  ORDER BY points DESC, goals_difference DESC;

Masalah selesai.

Bagaimana kalau datanya tidak berasal dari tabel database?

Read the rest of this entry »

  • Facebook
  • Twitter
  • Google Plus
  • LinkedIn
  • RSS
  • Print

Permanent link to this article: http://www.muhammadalvin.net/2012/01/pengurutan-multi-kolom-dengan-java/

Jan 16 2012

Mengenal Cross-Site Scripting (XSS)

Cross-site scripting (untuk selanjutnya akan disebut sebagai XSS) merupakan celah keamanan (security vulnerability)  yang biasa ditemukan di aplikasi berbasis web. Celah keamanan ini memungkinkan penyerang memasukkan (inject) kode tertentu yang bersifat client-side (misalnya JavaScript, CSS). Kode yang di-inject oleh penyerang tersebut akan dilihat dan dijalankan juga oleh pengguna lain. Akibat dari celah keamanan ini cukup bervariasi, mulai dari sekedar mengganggu, merusak tampilan web, hingga pencurian data seperti cookie.

Contoh halaman web yang memiliki celah keamanan ini bisa dilihat di sini.

Pertama, coba isikan sesuatu secara normal (misalnya nama = alvin, komentar = hello world). Apa yang terjadi? Tentu saja tidak ada masalah. Nama dan komentar akan  muncul sesuai dengan apa yang diinputkan.

Sekarang, coba isikan komentar yang ‘sedikit aneh’. Masukkan komentar yang berisi tag HTML, misalnya sebagai berikut:

Halo... ini contoh teks <b>bold</b> dan <u>underline</b>...

Apa yang terjadi? Komentar Anda muncul seperti ini:

Halo… ini contoh teks bold dan underline.

Nah, kode HTML yang kita sisipkan diproses oleh browser. Cobalah minta teman Anda untuk membuka halaman tersebut (dari komputer lain). Maka ia akan memperoleh hasil yang sama. Ini berarti si penyerang (dalam contoh ini adalah kita) berhasil meng-inject-kan kode buatannya. Hal seperti ini yang disebut celah keamanan Cross-Site Scripting. Ini harusnya tidak boleh terjadi. Bayangkan jika si penyerang menyisipkan kode berikut:

Halo...
<script type="text/javascript">
window.onload = function() {
    document.getElementsByTagName("body")[0].innerHTML = '<h1>This web is hacked!</h1>';
}
</script>

Atau komentar berikut yang sangat mengganggu pengguna lain (pengguna lain akan mendapatkan alert/popup yang tidak pernah berakhir):

<script type="text/javascript">
while (true) {
    alert('Sekarang jam ' + (new Date()).toUTCString());
}
</script>

Atau mungkin seperti ini:

Web ini bagus.
<script type="text/javascript">
if (confirm('Tapi sayang ada celah keamanannya! Klik OK untuk mempelajari celah keamanan tsb!')) {
  document.location.href = 'http://www.muhammadalvin.net/2012/01/mengenal-cross-site-scripting/';
}
</script>

Yang mengarahkan pengguna ke halaman lain.

Cara mengatasinya cukup sederhana. Jika menggunakan PHP, tambahkan htmlentities() sebelum menampilkan hasil inputan dari pengguna. Misalnya kode berikut:

echo 'Nama : ' . $nama;

Diubah menjadi:

echo 'Nama : ' . htmlentities($nama);

Pastikan Anda menggunakan fungsi tersebut di setiap bagian yang bertugas menampilkan hasil inputan dari pengguna.

Buat yang ingin tahu secara detail tentang XSS, simak pembahasan berikut.

Andaikan Anda membuat halaman HTML (index.html) berikut:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <title>Demo Cross-Site Scripting</title>
    </head>
    <body>
        <form action="hasil.php" method="post">
            <p><label for="nama">Nama:</label><br />
            <input type="text" name="nama" id="nama" /></p>
            <p><label for="komentar">Komentar:</label><br />
            <textarea name="komentar" id="komentar" cols="40" rows="5"></textarea></p>
            <p><input type="submit" value="Kirim" /></p>
        </form>
    </body>
</html>

Kemudian halaman PHP berikut (hasil.php) yang bertugas memproses hasil input dari halaman index.html:

<?php
$nama = (isset($_POST['nama']) ? $_POST['nama'] : '');
$komentar = (isset($_POST['komentar']) ? $_POST['komentar'] : '');

echo '<p>Nama:<br />' . $nama . '</p>';
echo '<p>Komentar:<br />' . $komentar . '</p>';

Saat Anda menjalankan index.html, akan muncul sebuah form dengan dua field. Jika Anda mengisi nama dengan test dan komentar dengan hello world, maka ketika di-submit (dengan menekan tombol Kirim), hasil.php akan memprosesnya sebagai berikut:

$nama = (isset($_POST['nama']) ? $_POST['nama'] : '');
// maka $nama berisi: test

$komentar = (isset($_POST['komentar']) ? $_POST['komentar'] : '');
// dan $komentar berisi: hello world

echo '<p>Nama:<br />' . $nama . '</p>';
// sesuai dengan nilai di variabel $nama di atas,
// maka akan di-echo: <p>Nama:<br />test</p>

echo '<p>Komentar:<br />' . $komentar . '</p>';
// sesuai dengan nilai di variabel $komentar di atas,
// maka akan di-echo: <p>Komentar:<br />hello world</p>

Di sini tidak ada masalah. Jika Anda coba jalankan, maka hasil sesuai dengan yang diharapkan.

Masalah muncul ketika misalnya komentar yang dimasukkan adalah ini adalah contoh teks <b>bold</b>. Halaman hasil.php akan memprosesnya sebagai berikut:

$komentar = (isset($_POST['komentar']) ? $_POST['komentar'] : '');
// $komentar berisi: ini adalah contoh teks <b>bold</b>

echo '<p>Komentar:<br />' . $komentar . '</p>';
// sesuai dengan nilai di variabel $komentar di atas,
// maka akan di-echo: <p>Komentar:<br />ini adalah contoh teks <b>bold</b></p>

Browser tidak pernah tau bahwa ini adalah contoh teks <b>bold</b> datangnya dari web developer yang membuat halaman atau dari isian pengguna yang iseng. Hasilnya, browser akan memproses kode HTML yang ada di dalamnya, sehingga akan menampilkan tulisan “bold” dalam keadaan bercetak tebal, hasil dari tag HTML <b> dan </b> tersebut.

Hal yang sama terjadi untuk JavaScript. Pengguna yang iseng bisa menyisipkan kode JavaScript yang diapit oleh tag HTML <script type=”text/javascript”> dan </script>. Hasilnya tentu saja kode JavaScript tersebut akan dijalankan oleh browser.

Cara mengatasinya adalah dengan meng-escape karakter-karakter spesial HTML, seperti:

  • & menjadi &amp;
  • < menjadi &lt;
  • > menjadi &gt;
  • ” menjadi &quot;

Anda bisa melakukan find-replace secara manual, atau menggunakan fungsi yang disediakan oleh bahasa pemrograman yang digunakan. Sebagai contoh fungsi htmlentities() yang disediakan oleh PHP.

Nah, XSS ini terjadi saat menampilkan sesuatu ke web browser. Celah keamanan sebaliknya, terjadi saat menyimpan sesuatu dari web browser (hasil input pengguna) ke database biasa dikenal dengan SQL injection. Selain kedua jenis tersebut, masih ada lagi celah keamanan yang lain, misalnya Cross-site Request Forgery (CSRF).

———-

Referensi:

  • Facebook
  • Twitter
  • Google Plus
  • LinkedIn
  • RSS
  • Print

Permanent link to this article: http://www.muhammadalvin.net/2012/01/mengenal-cross-site-scripting/

Jan 15 2012

#JLEBmoment #SRM529

SELECT * FROM right_sidebar WHERE title = 'Twitter - @mhdalvin' 
  AND topic = 'TopCoder SRM 529' ORDER BY timestamp;
  • Malam yg penuh kesialan -_-” (25 minutes ago)
  • #JLEBmoment itu saat mengikuti #SRM sama sekali nggak ngerti maksud problem easy (19 minutes ago)
  • #JLEBmoment itu saat mengikuti #SRM terpaksa close problem easy lalu open problem medium dlm keadaan sama sekali belum coding problem easy. (17 minutes ago)
  • #JLEBmoment itu saat di tengah coding, tiba-tiba lupa cara pakai java.util.HashMap dan java.util.ArrayList (16 minutes ago)
  • #JLEBmoment itu saat coding problem medium tiba2 ‘Connection to the server is lost. Logging off’ (14 minutes ago)
  • #JLEBmoment itu saat tidak bisa login lagi setelah ter-logout karena internet putus. Ternyata internet nya masih putus. (12 minutes ago)
  • #JLEBmoment itu saat punya smartphone n ada paket intenet tapi gk bisa tethering, karena berada di daerah yg sulit sinyal Telkom53l (10 minutes ago)
  • #JLEBmoment itu saat nggak pulang ke rumah demi koneksi internet 5 Mbps, tiba2 koneksi nya putus (8 minutes ago)
  • #JLEBmoment itu saat ini. Titik. (3 minutes ago)

Oke, satu lagi tambahan:

#JLEBmoment itu adalah saat problem medium hampir solve, lalu muncul ‘Coding phase is ended’

  • Facebook
  • Twitter
  • Google Plus
  • LinkedIn
  • RSS
  • Print

Permanent link to this article: http://www.muhammadalvin.net/2012/01/jlebmoment-srm529/

Jan 02 2012

Kalender Maya

Pagi ini, 2 Januari 2012, jalanan begitu sunyi. Sepertinya banyak yang cuti bersama. Mungkin karena itu juga, saya tiba di kantor terlalu awal, sebelum jam 8.00. Masih terlalu pagi, jadi saya buka-buka twitter, lihat-lihat timeline, ketemu beberapa twit berita yang cukup menarik. Salah satunya tentang isu kiamat di Desember 2012 (yang katanya sebagai efek dari berakhirnya sistem penanggalan pada kalender suku Maya) yang ditolak oleh suku Maya sendiri. Ada seorang peneliti yang cukup mengerti dengan suku Maya. Menurut informasi yang ia peroleh, suku Maya sendiri tidak pernah memprediksi itu. Memang benar salah satu siklus penanggalan akan berakhir di Desember 2012, tetapi itu hanyalah merupakan akhir dari siklus penanggalan, bukan akhir dunia. Setelah akhir itu, akan ada siklus penanggalan berikutnya. Dan katanya, ini bukan yang pertama terjadi. Apapun itu, sebagai muslim, saya tetap percaya bahwa datangnya kiamat tidak akan ada yang tahu, selain Allah SWT.

Seperti biasa, keingintahunan saya mendadak muncul. Saya googling tentang sistem penanggalan suku Maya tersebut. Tentu saja saya mendapatkan artikel dari Wikipedia tentang itu. Tetapi yang membuat saya tertarik adalah ini:

http://livearchive.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=459&page=show_problem&problem=3516

Setelah membaca dan melihat batasan soal tersebut, saya berpikir ini soal yang cukup mudah. Soal ini tidak butuh algoritma-algoritma rumit untuk menyelesaikannya.

Jenis soal: ad-hoc

Analisis: Sistem penanggalan Haab memiliki 365 hari dalam setahun, dengan batasan tahun adalah 5000. Itu berarti total hari sejak hari pertama sampai hari terakhir masih kurang dari 2 juta. Bukan angka yang besar, dan tipe data integer (32 bit) masih memiliki banyak tempat untuk itu.

Oke, mari kita coding!

Awalnya mau pakai Java, tetapi karena belum pernah submit dengan Java di LiveArchive, saya pilih bahasa yang dulu sering saya gunakan, C++.

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

int main()
{
    string haab[19] = { "pop", "no", "zip", "zotz", "tzec", "xul", "yoxkin",
        "mol", "chen", "yax", "zac", "ceh", "mac", "kankin", "muan", "pax",
        "koyab", "cumhu", "uayet" };    
    string tzolkin[20] = { "imix", "ik", "akbal", "kan", "chicchan", "cimi",
        "manik", "lamat", "muluk", "ok", "chuen",  "eb", "ben", "ix", "mem",
        "cib", "caban", "eznab", "canac", "ahau" };

    int nTC; cin >> nTC; cin.ignore();
    cout << nTC << endl; // output-nya butuh ini!
    string input;
    while (nTC-- > 0) {
        getline(cin, input);

        int d = 0;
        string m = "";
        int y = 0;

        int flag = 1;
        for (int i = 0, n = input.size(); i < n; i++) {
            char c = input[i];
            if (c == '.') {
                flag = 2;
            } else if (c == ' ' && flag == 2) {
                flag = 3;
            } else if (c == ' ' && flag == 3) {
                flag = 4;
            } else if (flag == 1) {
                d *= 10; d += c - '0';
            } else if (flag == 3) {
                m += c;
            } else if (flag == 4) {
                y *= 10; y += c - '0';
            }
        }

        int indeksBulan = -1;
        for (int i = 0; i < 19; i++) {
            if (haab[i] == m) {
                indeksBulan = i;
                break;
            }
        }

        unsigned int jumlahHari = (y * 365) + (20 * indeksBulan) + d;
        // cout << jumlahHari << endl;

        unsigned tahunTzolkin = jumlahHari / 260;
        unsigned sisa = jumlahHari % 260;

        int a = 0, b = 0;
        for (int i = 0; i < sisa; i++) {
            a = (a + 1) % 13;
            b = (b + 1) % 20;
        }

        cout << (a + 1) << " " << tzolkin[b] << " " << tahunTzolkin << endl;
    }

    // system("pause");
}

Array haab dan tzolkin tidak diketik satu persatu itemnya. Ada cara cepat dengan bantuan Notepad++ dan regular expression.

Cara memparsing input nya juga cukup ‘bodoh’ :D . Tapi that’s OK lah, itu gak jadi persoalan. Hasil parsing adalah mengisi 3 variabel berikut:

  • d = tanggal di kalendar Haab (input), dimulai dari 0.
  • m = bulan di kalender Haab (input).
  • y = tahun di kalender Haab (input), dimulai dari 0.

Langkah pertama: Kalender Haab terdiri dari 365 hari dalam setahun. Jika y = 0, maka tanggal tersebut belum setahun. Jika y = 1, maka tanggal tersebut sudah lebih setahun. Jika y = 2, maka tanggal tersebut sudah lebih 2 tahun. Artinya, berapapun nilai y, tanggal tersebut sudah melebihi y tahun, atau y * 365 hari.

Langkah kedua: Kalender Haab terdiri dari 19 bulan. 18 bulan pertama (pop s.d. cumhu) memiliki 20 hari, dan bulan terakhir (uayet) memiliki 5 hari. Suatu tanggal di bulan pertama, berarti tanggal tersebut belum sebulan pada tahun tersebut. Suatu tanggal di bulan kedua, berarti tanggal tersebut sudah lebih 1 bulan pada tahun tersebut. Suatu tanggal di bulan ketiga, berarti tanggal tersebut sudah lebih 2 bulan pada tahun tersebut. Dan seterusnya sampai suatu tanggal di bulan ke-19, berarti tanggal tersebut sudah lebih 18 bulan pada tahun tersebut. Nah, karena kebetulan bulan pertama sampai bulan ke-18 terdiri dari 20 hari, maka kalikan saja dengan 20 berapa bulan yg sudah dilewati.

Langkah ketiga: Tambahkan angka tanggal.

Hasil akhirnya begini:

jumlahHari = (y * 365) + (20 * indeksBulan) + d;

indeksBulan = 0 untuk bulan pertama (pop), 1 untuk bulan kedua (no), 2 untuk bulan ketiga (zip), dst.

Sebenarnya ini nggak begitu pas. Kenapa? Coba perhatikan tanggal 0. pop 0 yang merupakan tanggal pertama di kalender Haab. Menggunakan rumus di atas, maka:

jumlahHari = (0 * 365) + (20 * 0) + 0 = 0

Hari pertama, kenapa 0? Bukannya 1? Ya pertanyaan bagus. Jawabannya adalah karena kita akan menghitung dari 0, bukan 1. Ini akan memudahkan kita dalam baris kode selanjutnya jika dibandingkan dengan menghitung dari 1.

Kalender Tzolkin memiliki 13 periode dan 20 hari. Berdasarkan permutasi yang dicontohkan di soal, kita bisa mengetahui bahwa ada maksimum 13 * 20 hari = 260 hari di kalender Tzolkin.

1 hari di kalender Haab berarti 1 hari (kurang dari setahun) di kalender Tzolkin, 2 hari di kalender Haab berarti 2 hari (kurang dari setahun) di kalender Tzolkin, …, 260 hari di kalender Haab berarti 1 tahun di kalender Tzolkin, 261 hari di kalender Haab berarti 1 tahun lebih 1 hari di kalender Tzolkin, dst. Dengan kata lain, 1 hari sampai dengan 260 hari belum melewati setahui kalender Tzolkin. Karena kita menghitung dari 0, maka berapa tahun di kalender Tzolkin yang sudah dilewati dapat dengan mudah diperoleh dengan membaginya dengan 260 lalu mengambil bagian integernya. 0 / 260 = 0; 1 / 260 = 0; 259 / 260 = 0. Akan sedikit lebih sulit jika menghitung dari 1, karena 260 / 260 = 1, padahal 260 hari belum melewati setahun tahun Tzolkin.

Setelah mendapatkan berapa tahun Tzolkin, hitung sisanya dengan jumlahHari % 260. Tentukan tanggal dan bulan apa yang tepat dari sisa tersebut. Di sini lagi-lagi saya menghitung dari 0. Ini sangat membantu, karena ada operasi modulo dan penggunaan array (indeks array juga dimulai dari 0).

Saat menampilkan, pastikan untuk menambahkan tanggal dengan 1, karena tanggal pertama di kalender Tzolkin adalah 1, bukan 0.

———-

Mestinya soal ini Accepted dalam submission pertama, tetapi gara2 tidak teliti membaca apa yang diminta di output, jadi Wrong Answer beberapa kali. Masalahnya sepele: baris pertama output adalah banyaknya output, yang nilainya sama dengan jumlah test case. Setelah itu, barulah output.

Yang lebih parahnya lagi, hal tersebut lama disadari. Bahkan sampai mencoba hal-hal ini:

if (d >= 20) {
    cout << 1/0; // pembagian dengan 0 untuk memancing Runtime Error
}

Karena di soal nggak dijelaskan kalau input-an pasti valid, maka’a sampai repot-repot ngecek itu. Dan ternyata setelah di-submit, memang benar nggak Runtime Error, karena input-an nya valid.

Akhirnya setelah disadari, 1 baris berikut ditambahkan:

cout << nTC << endl;

Dan hasil submit-pun berubah menjadi Accepted. Tanpamu, semua itu tak berarti! Tanpa baris tersebut, semua jawaban yang sudah benar tetap sia-sia.

  • Facebook
  • Twitter
  • Google Plus
  • LinkedIn
  • RSS
  • Print

Permanent link to this article: http://www.muhammadalvin.net/2012/01/kalender-maya/

Older posts «