Pendahuluan
Halo, jumpa lagi di hari Jumat!
Karena isu keamanan akhir-akhir ini semakin ketat, saya merasakan perlunya pembelajaran kepada masyarakat Indonesia mengenai penggunaan enkripsi yang tepat. Entahlah, mungkin ini juga karena saya meneliti Owncloud terlalu jauh. Atau mungkin ini sekedar tulisan menambah kuota tulisan saya di blog. Ilmu memang untuk dibagi.
Orang pasti sudah tahu tentang BEAST, CRIME, dan HEARTBLEED. BEAST adalah proof-of-concept serangan terhadap enkripsi TLSv1.0 yang menyebabkan sebuah domain dapat dibajak dari implementasi TLS v1.0 yang buruk di sistem operasi. Lalu, ada CRIME yang menyerang implementasi kompresi HTTP pada TLS dan SPDY. Yang menghebohkan berikutnya adalah HEARTBLEED yang menyerang implementasi cacat OpenSSL pada implementasi ekstensi TLS heartbeat.
Yang terakhir dan teranyar adalah POODLE, eksploit terhadap SSLv3 yang menyebabkan sekarang ini orang dipaksa untuk mematikan SSLv3. Ya, kecuali Anda menggunakan IE6/7 pada Windows XP yang belum diperbaharui, sebenarnya SSLv3 sudah lama tidak diperlukan. Bahkan, sebaiknya Anda memaksa peramban Anda langsung menggunakan TLS v1.2.
Ekstensi AES-NI
Tapi… tapi… bukankah menggunakan enkripsi membuat peladen kurang responsif?
Itu dulu! Sekarang, ‘kan, sudah ada ekstensi AES-NI pada prosesor x86. Jadi, enkripsi dilakukan secara langsung oleh CPU. Saya melakukan eksperimen kecil untuk memperlihatkan perbedaan operasi biasa dan menggunakan AES-NI.
Operasi biasa menggunakan instruksi CPU normal.
$ OPENSSL_ia32cap="~0x200000200000000" openssl speed -elapsed -evp aes-128-cbc
You have chosen to measure elapsed time instead of user CPU time.
Doing aes-128-cbc for 3s on 16 size blocks: 34349970 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 64 size blocks: 8984170 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 256 size blocks: 2337382 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 1024 size blocks: 589989 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 8192 size blocks: 74022 aes-128-cbc's in 3.00s
OpenSSL 1.0.1i 6 Aug 2014
built on: Fri Aug 8 06:23:32 WIB 2014
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
compiler: x86_64-pc-linux-gnu-gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN -DTERMIO -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -O2 -pipe -march=native -mtune=native -fomit-frame-pointer -flto=8 -floop-interchange -ftree-loop-distribution -floop-strip-mine -floop-block -ftree-vectorize -fno-strict-aliasing -Wa,--noexecstack
The 'numbers' are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-128-cbc 183199.84k 191662.29k 199456.60k 201382.91k 202129.41k
Sedangkan berikut operasi menggunakan instruksi AES-NI.
$ openssl speed -elapsed -evp aes-128-cbc
You have chosen to measure elapsed time instead of user CPU time.
Doing aes-128-cbc for 3s on 16 size blocks: 99416661 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 64 size blocks: 27157194 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 256 size blocks: 7746016 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 1024 size blocks: 2005119 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 8192 size blocks: 253147 aes-128-cbc's in 3.00s
OpenSSL 1.0.1i 6 Aug 2014
built on: Fri Aug 8 06:23:32 WIB 2014
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
compiler: x86_64-pc-linux-gnu-gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN -DTERMIO -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -O2 -pipe -march=native -mtune=native -fomit-frame-pointer -flto=8 -floop-interchange -ftree-loop-distribution -floop-strip-mine -floop-block -ftree-vectorize -fno-strict-aliasing -Wa,--noexecstack
The 'numbers' are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-128-cbc 530222.19k 579353.47k 660993.37k 684413.95k 691260.07k
Berikut tabel hasilnya:
Instruksi CPU |
Tipe |
16-bit |
64-bit |
256-bit |
1024-bit |
8192-bit |
AES-NI |
aes-128-cbc |
530222,19 |
579353,47 |
660993,37 |
684413,95 |
691260,07 |
Normal |
183199,84 |
191662,29 |
199456,6 |
201382,91 |
202129,41 |
Performa |
2,8942284557 |
3,0227827811 |
3,313970909 |
3,3985701667 |
3,4198886248 |
Total Performa AES-NI |
3,2098881874 |
Tampak bahwa dalam kasus ini, penggunakan AES-NI pada OpenSSL meningkatkan performa 3 kali lipat.
Dukungan AES-NI
Untuk mengetahui apakah prosesor peladen Anda mendukung AES-NI, silakan lihat dengan:
$ cat /proc/cpuinfo | grep aes
flags : ... aes ...
Kalau didukung, akan ada tulisan ‘aes’. Biasanya, sih, untuk prosesor AMD dan Intel yang baru [baca: keluaran tahun-tahun ini] sudah mendukung instruksi AES-NI. Kalau pun belum, bisa langsung saja mengompilasi OpenSSL dengan menggunakan instruksi SSE4 atau AVX. Ya, tapi itu di luar cakupan tulisan ini agar tidak terlalu rumit.
Untuk Debian Wheezy, OpenSSL 1.0.1e yang digunakan akan secara otomatis mendeteksi AES-NI. Tidak perlu mengompilasi sendiri untuk versi Debian tersebut. Untuk sistem operasi yang lain, silakan konsultasi kepada Mbah Gugel.
Bila Anda menggunakan KVM atau Proxmox, pastikan Anda menggunakan tipe CPU Host. Cara lain adalah pastikan instruksi AES-NI diperbolehkan untuk KVM.
Konfigurasi NGINX
Karena OpenSSL transparan, maka tidak ada yang perlu dipusingkan oleh NGINX untuk menggunakan AES-NI. NGINX hanya perlu memberitahukan protokol enkripsi yang dipakai untuk HTTPS. Untuk itu, perhatikan contoh konfigurasi NGINX:
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name www.contoh.aja;
server_name_in_redirect on;
port_in_redirect on;
access_log /var/log/nginx/normal.access.log;
error_log /var/log/nginx/normal.error.log;
## redirect http to https ##
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443 ssl spdy;
listen [::]:443 ipv6only=on ssl spdy;
server_name www.contoh.aja;
server_name_in_redirect on;
port_in_redirect on;
ssl on;
ssl_certificate /etc/nginx/ssl.cert;
ssl_certificate_key /etc/nginx/ssl.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
access_log /var/log/nginx/ssl.access.log;
error_log /var/log/nginx/ssl.error.log;
## HERE PHP ENGINE AND OTHER REWRITE RULES ##
}
Saya akan mencoba menjelaskan beberapa bagian yang penting. Saya mengasumsikan Anda sudah tahu mengonfigurasi NGINX secara dasar sehingga saya tak perlu menjelaskan semuanya. Atau, setidaknya Anda bisa mencari langsung di Internet.
Saya sengaja tidak menyertakan aturan FastCGI PHP dan aturan-aturan rewrite untuk mengurangi kompleksitas kode. Ada banyak tutorial dasar untuk menyertakan aturan FastCGI. Lagipula, untuk aturan-aturan rewrite tergantung kepada aplikasi yang kita gunakan (Drupal, WordPress, dsb.).
Yak, langsung saja.
Mendengar di IPv4 dan IPv6
Berikut sintaksis agar NGINX mendengar semua antarmuka jaringan (IPv4 dan IPv6).
listen 80;
listen [::]:80 ipv6only=on;
Ada alasan mengapa mengaktifkan dual stack. Universitas Indonesia (UI) sudah sejak lama memiliki satu blok (/16) IPv4 kelas B. Karena termasuk historical member dari IANA, UI juga beruntung mendapatkan satu blok /48 IPv6. Itu sebabnya, hampir semua peladen UI sudah memiliki IPv6 sendiri berikut IPv4 publik.
Mengarahkan Semua ke HTTPS
Berikut sintaksis untuk mengarahkan koneksi HTTP ke HTTPS.
rewrite ^ https://$server_name$request_uri? permanent;
Ada tutorial lama yang menyampur koneksi HTTPS dan HTTP. Hal ini tidak sesuai dengan prinsip keamanan. Bila memang situs ingin aman sepenuhnya, maka harus semuanya harus menggunakan HTTPS. Konten campuran (berisi HTTP dan HTTPS) tidak disarankan dan beberapa peramban akan cerewet tentang itu.
Mengaktifkan SPDY
Berikut sintaksis agar NGINX menggunakan SSL (HTTPS) dengan SPDY.
listen 443 ssl spdy;
listen [::]:443 ipv6only=on ssl spdy;
Untuk akselerasi HTTPS, Google mengembangkan teknik SPDY. Hampir semua peramban modern mendukung protokol SPDY. Saya pernah membahas ini.
Mengaktifkan SSL
Baris-baris inilah yang mengaktifkan enkripsi HTTPS (SSL).
ssl on;
ssl_certificate /etc/nginx/ssl.cert;
ssl_certificate_key /etc/nginx/ssl.key;
Baris ssl_certificate mengarahkan ke berkas sertifikat peladen. Ada tiga jenis skenario untuk berkas sertifikat peladen:
- Untuk menambah legitimasi, biasanya sertifikat ditandatangani oleh Certificate Authority (CA) yang sudah diakui. StartSSL menyediakan layanan ini dengan gratis. Kalau mau yang murah ada RapidSSL atau Komodo. Kalau mau lebih bonafide, gunakan VeriSign. Mereka ini biasanya sertifikat utamanya (root certificate) sudah dipasang di sistem operasi/peramban. Root certificate adalah sertifikat CA yang dipakai untuk melegitimasi sertifikat sebuah server.
- Ada juga organisasi yang membuat root certificate sendiri. Biasanya, mereka memasang sendiri root certificate ke sistem operasi/peramban pengguna. Ada banyak tutorial tentang itu, terutama Windows Server dan UNIX.
- Yang paling jamak digunakan di tutorial-tutorial biasanya menggunakan sertifikat yang ditandatangani sendiri (self-signed).
Silakan pilih skenario yang terbaik. Untuk situs bisnis biasanya menggunakan CA pihak ketiga (poin 1). Namun, untuk Intranet biasanya menggunakan poin 2.
Baris berikutnya ssl_certificate_key mengarahkan berkas kunci privat peladen. Pastikan berkas ini hanya bisa diakses baca-saja oleh root (0400).
Parameter Tambahan
Berikut parameter tambahan yang opsional. Parameter-parameter ini yang memperkuat enkripsi situs.
Hanya Gunakan TLS
Protokol SSLv3 sudah tamat semenjak POODLE beberapa hari yang lalu. Banyak yang menyarankan untuk mematikan protokol ini. Ya, berhubung protokol ini sudah sangat lama, wajar saja. Lagipula, hanya IE6/7 yang menggunakan Windows XP SP3 yang belum ditambal saja yang terpengaruh. Sisanya, dunia sudah mengenal TLS sejak lama.
Ya sudah, cukup aktifkan semua versi protokol TLS saja.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
Protokol TLS pun sebenarnya tidak begitu aman. Kalau mau paranoid, hanya aktifkan TLSv1.2 saja. Tentu saja, ini mengurangi jumlah pengunjung dan peramban yang bisa mengakses situs kita.
Gunakan SHA256 AES-GCM dengan Forward Secrecy dan RC4 Sebagai Cadangan
Semenjak tahun 2011, SHA1 dianggap sudah tidak aman lagi. Lebih parah lagi, Google akan mempenalti situs-situs yang masih menggunakan SHA1 pada 1 Januari 2017. Artinya, semua situs yang masih memakai sertifikat dengan tanda tangan SHA1 akan dianggap tidak aman oleh produk-produk Google.
Bila Anda masih baru mau memasang sertifikat, gunakan sertifikat dengan tanda tangan SHA256. Atau kalau lebih bagus lagi, gunakan SHA387. Tetapi, untuk SHA387 masih jarang dan lagi mahal.
Ada banyak protokol pertukaran kunci dan saya tidak mau terlalu detail. Saat ini protokol yang aman dari gangguan adalah AES-GCM dan RC4. Protokol RC4 sudah lama dan relatif aman. Sedangkan GCM masih relatif baru, sehingga beberapa peramban lama tidak mendukung.
[Lama itu hitungannya 10 s.d. 20 tahun yang lalu, ya, kawan-kawan.]
Saat ini RC4 disarankan untuk ditinggalkan. Bukan berarti dia tidak aman. Sudah ada metodenya, tetapi untuk bisa membobol RC4 saat ini memerlukan sumber daya yang sangat besar. Jadi, RC4 relatif cukup aman.
Penggunaan AES-GCM disarankan oleh karena adanya instruksi AES-NI yang mempercepat percepat perhitungan. Teknik ini peningkatan implementasi dari AES-CBC dengan menggunakan instruksi perangkat keras. Itu sebabnya, AES-CBC disarankan ditinggalkan.
Berikut instruksinya.
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
Oh, iya, satu lagi. Dalam konfigurasi ini diaktifkan mode Forward Secrecy yang ada di TLSv1.2.
Mengaktifkan Urutan Enkripsi Di Sisi Server
Instruksinya:
ssl_prefer_server_ciphers on;
Instruksi ini mengakibat peladen akan menyuruh klien untuk menggunakan metode enkripsi yang diinginkan sesuai dengan urutan. Ini mengurangi kemungkinan klien yang sudah mendukung TLSv1.2 malah menggunakan versi terdahulu karena konfigurasi perambannya. Hal ini bisa memitigasi terhadap serangan BEAST.
Menyimpan Sesi SSL
Instruksinya:
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
Untuk keperluan optimasi, NGINX dapat menyimpan sesi SSL pada tembolok. Ada dua jenis yang didukung. Yang pertama, tembolok tersebut disimpan oleh NGINX sehingga bisa diakses oleh sesama proses-proses pekerja NGINX. Yang kedua, per pekerja menggunakan tembolok yang disediakan oleh OpenSSL. Disarankan untuk menggunakan tembolok NGINX saja.
Menurut NGINX, 1 MB mampu menampung 4000 sesi. Konfigurasi ini menggunakan 10MB sehingga kira-kira ada 40000 sesi yang didukung. Setiap sesi ini disimpan selama 10 menit saja. Silakan dikonfigurasikan sesuai kemampuan peladen Anda.
Terakhir
Setelah semua selesai, silakan menyalakan ulang NGINX. Mari saya rekap untuk Anda:
- Gunakan SPDY untuk mempercepat koneksi HTTPS.
- Gunakan kunci dengan algoritma SHA256 atau lebih yang sudah divalidasi oleh CA.
- Gunakan protokol TLS teranyar dengan AES-GCM dengan RC4 sebagai cadangan.
- Gunakan tembolok untuk mengoptimasi penggunaan TLS.
Anda pun sudah memiliki peladen yang cukup handal. Anda bisa mempelajari teknik-teknik tambahan lain mengenai SSL, misalnya menggunakan OCSP.
Terakhir, Anda perlu mengedukasi pengguna Anda agar tidak memberikan sandi kepada siapa pun dan mengganti sandi secara periodik, misalnya 6 bulan sekali. Percuma punya infrastruktur yang handal tanpa pengguna yang paham.
Nota Bene
Gunakan pihak ketiga untuk menguji SSL. Saya menggunakan perkakas dari Qualys SSL Lab. Contoh hasil pengujian konfigurasi SSL pada Blog Staff UI.

SSL Labs test on Blog Staff UI. Yeah, we need to upgrade into SHA256. The certificate is issued not long ago.
Bacaan Lebih Lanjut