Pustaka standar Go menyediakan pustaka crypto/tls, implementasi dari Transport Layer Security (TLS), protokol keamanan paling penting pada Internet, yang menjadi komponen dasar dari HTTPS. Pada Go 1.17 kita membuat konfigurasi TLS lebih mudah, aman, dan efisien dengan memilih pasangan cipher yang sesuai secara otomatis.

Bagaimana pasangan cipher bekerja

Pasangan cipher berawal dari Secure Socket Layer (SSL), yang dikenal juga dengan istilah jenis cipher. Contoh identifikasi dari pasangan cipher ini yaitu TLS_RSA_WITH_AES_256_CBC_SHA atau TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 yang menampilkan algoritma yang digunakan untuk pertukaran kunci, sertifikat autentikasi, dan enkripsi dalam sebuah koneksi TLS.

Pasangan cipher dinegosiasikan saat handshake TLS: pada pesan yang pertama, Client Hello, klien mengirim daftar pasangan cipher yang didukung, kemudian peladen memilih salah satu dari daftar tersebut, memberitahu klien pilihannya. Klien mengirim daftar pasangan cipher yang didukung sesuai dengan urutan yang mereka inginkan, dan peladen bebas memilih sesuai yang mereka inginkan. Biasanya, peladen akan memilih pasangan cipher pertama yang sama-sama didukung sesuai dengan urutan klien atau sesuai urutan pilihan peladen, bergantung pada konfigurasi peladen.

Pasangan cipher adalah salah satu dari banyak parameter yang dinegosiasikan —algoritma curve dan signature biasanya dinegosiasikan lewat ekstensi tambahan—namun ia yang paling kompleks dan dikenal banyak orang, dan satu-satunya yang mana pengembang dan administrator terlatih selama bertahun-tahun.

Pada TLS 1.0-1.2, semua parameter tersebut berinteraksi dalam jaringan kompleks yang bergantung satu sama lain: contohnya dukungan terhadap sebuah sertifikat bergantung pada algoritma signature, curves, dan pasangan cipher yang tersedia. Pada TLS 1.3 semuanya telah disederhanakan: pasangan cipher hanya perlu menentukan algoritma enkripsi simetris, sementara dukungan curves mengatur pertukaran kunci dan dukungan algoritma signature yang dipakai pada sertifikat.

Pengembang bebas dari pemilihan pasangan cipher

Kebanyakan peladen HTTPS dan TLS mendelegasikan pilihan pasangan cipher dan urutannya ke operator peladen atau pengembang aplikasi. Hal ini adalah pilihan kompleks yang membutuhkan pengetahuan yang khusus dan terbarukan.

Beberapa pasangan cipher tua memiliki komponen yang tidak aman, beberapa membutuhkan implementasi yang sangat hati-hati dan kompleks supaya dapat aman, dan beberapa hanya aman jika klien menerapkan semacam mitigasi atau bahkan perangkat keras tertentu. Terlepas dari keamanan dari setiap komponen, pasangan cipher yang berbeda dapat menyediakan properti keamanan yang sangat drastis berbeda pula untuk semua koneksi, seperti pasangan cipher tanpa ECDHE atau DHE tidak menyediakan kerahasiaan —properti yang mana koneksi tidak bisa secara pasif di-dekripsi dengan kunci sertifikat. Terakhir, pemilihan pasangan cipher yang didukung memengaruhi kompatibilitas dan performa, dan membuat perubahan —tanpa pengetahuan yang terbarukan dari ekosistem ini— dapat menyebabkan masalah koneksi pada klien-klien yang tua, meningkatkan penggunaan sumber daya pada peladen, atau cepat menghabiskan baterai pada klien mobil.

Cara pemilihan ini sangat "mistis" dan "rapuh" sehingga ada beberapa perkakas untuk membantu operator, seperti situs Pembangkit Konfigurasi SSL dari Mozilla ini.

Kenapa dan bagaimana bisa seperti ini?

Awalnya, komponen-komponen individu kriptografi sering kali rusak. Di tahun 2011, saat serangan BEAST merusak pasangan cipher CBC dengan cara yang hanya klien yang dapat memperbaikinya, peladen bergerak untuk memilih RC4, yang pada saat itu belum terinfeksi. Di tahun 2013, saat diketahui bahwa RC4 juga rusak, peladen kembali menggunakan CBC. Saat Lucky Thirteen memberitahu bahwa pasangan cipher CBC sangat sulit diimplementasikan disebabkan rancangannya, maka tidak ada pilihan lain sehingga implementasi CBC harus loncat-loncat dan pekerjaan tersebut tetap gagal selama bertahun-tahun. Pasangan cipher yang bisa dikonfigurasi dan kelincahan kriptografi biasanya menyediakan jaminan bahwa bila sebuah komponen rusak maka ia bisa diganti langsung.

Kriptografi moderen secara signifikan sangat berbeda. Protokol-protokol masih tetap dapat rusak dari waktu ke waktu, namun biasanya jarang bagi komponen individu dapat rusak. Tidak ada pasangan cipher berbasis AEAD yang dirilis pada TLS 1.2 di tahun 2018 telah rusak. Saat ini kelincahan kriptografi adalah sebuah liabilitas: kompleksitas-nya bisa menyebabkan kelemahan atau downgrade, dan hanya diperlukan untuk performa dan pemenuhan syarat (misalnya, aturan keamanan perusahaan).

Cara penambalan aplikasi juga berbeda antara dulu dengan sekarang. Model penambalan sekarang yaitu langsung pada perangkat lunak untuk celah-celah yang telah diketahui, yang merupakan fondasi dari pengembangan perangkat lunak yang aman, namun sepuluh tahun yang lalu hal seperti itu bukanlah praktik standar. Mengubah konfigurasi adalah opsi paling cepat untuk merespon bila ada pasangan cipher yang rusak, sehingga operator, lewat konfigurasi, bertanggung jawab sepenuhnya. Sekarang kita memiliki isu yang sebaliknya: semua peladen telah ditambal dan diperbarui namun tetap berjalan aneh, sub-optimal, atau tidak aman, karena konfigurasi mereka tidak pernah diubah.

Terakhir, peladen condong jarang diperbarui dibandingkan klien, oleh karena itu kurang dipercaya untuk memilih pasangan cipher. Namun, peladen-lah yang memutuskan pasangan cipher yang dipilih, sehingga pengaturan bawaan peladen yaitu membuat mereka memilih pasangan cipher berdasarkan urutan yang diberikan klien, bukan berdasarkan konfigurasi peladen. Hal ini ada bagusnya: peramban bisa melakukan pembaruan secara otomatis dan lebih sering diperbarui daripada peladen. Di sisi lain, sejumlah perangkat yang telah tua sekarang telah kadaluarsa dan mentok dengan konfigurasi TLS klien yang juga sudah lama, sehingga membuat peladen yang terbarukan lebih baik menentukan pilihan daripada beberapa klien mereka.

Bagaimanapun caranya kita bisa seperti ini, ini adalah kegagalan dari rekayasa kriptografi yang mengharuskan pengembang aplikasi dan operator peladen untuk menjadi ahli dalam pemilihan pasangan cipher, dan supaya pengetahuan mereka tetap terbarukan sehingga konfigurasi mereka tetap diperbaiki terus menerus. Jika mereka menerbitkan tambalan keamanan yang kita sediakan, itu saja sudah cukup.

Pembangkit konfigurasi SSL dari Mozilla sangat bagus, namun seharusnya ia tidak diperlukan.

Apakah kondisi sekarang akan lebih baik di masa depan?

Ada kabar baik dan kabar buruk tentang bagaimana semua ini menjadi tren beberapa tahun terakhir. Kabar buruknya adalah pemilihan urutan pasangan cipher semakin "bernuansa", karena ada sekumpulan pasangan cipher yang memiliki properti keamanan yang mirip. Pilihan terbaik dari sekumpulan pilihan tersebut bergantung pada perangkat keras yang tersedia dan sangat sulit dijabarkan dalam sebuah berkas konfigurasi. Pada sistem lain, yang awalnya berupa daftar pasangan cipher sekarang bergantung pada sintaksis kompleks atau flag tambahan seperti SSL_OP_PRIORITIZE_CHACHA.

Kabar baiknya yaitu TLS 1.3 secara drastis menyederhanakan pasangan cipher, dan ia terpisah dari TLS 1.0-1.2. Semua pasangan cipher pada TLS 1.3 aman, sehingga pengembang aplikasi dan operator peladen tidak perlu khawatir. Bahkan, beberapa pustaka TLS seperti BoringSSL dan crypto/tls pada Go tidak membolehkan mengonfigurasi mereka sama sekali.

Pasangan cipher dan paket crypto/tls

Go membolehkan pengembang mengatur pasangan cipher dalam TLS 1.0-1.2. Aplikasi bisa mengatur pasangan cipher dan preferensi urutan dengan Config.CipherSuites. Peladen memprioritaskan urutan preferensi dari klien secara bawaan, kecuali bila Config.PreferServerCipherSuites di set.

Saat kita mengimplementasikan TLS 1.3 pada Go 1.12, kita tidak membuat pasangan cipher TLS 1.3 bisa diatur, karena mereka kumpulan terpisah dari TLS 1.0-1.2 dan yang paling penting mereka semua aman, jadi tidak perlu mendelegasikan pilihan kepada aplikasi. Config.PreferServerCipherSuites tetap mengontrol urutan preferensi mana yang digunakan, dan preferensi pada sisi lokal bergantung pada ketersediaan perangkat keras.

Pada Go 1.14, kita mengeluarkan pasangan cipher yang didukung namun secara eksplisit mengembalikan mereka dengan urutan netral (diurut berdasarkan ID).

Pada Go 1.16, kita secara aktif mulai memilih pasangan cipher ChaCha20Poly1305 dibanding AES-GSM pada peladen saat kita mendeteksi bahwa peladen dan klien tidak memiliki dukungan perangkat keras untuk AES-GCM. Hal ini karena AES-GCM sangat sukar diimplementasikan secara efisien dan aman tanpa dukungan dedikasi perangkat keras (seperti kumpulan instruksi AES-NI dan CLMUL).

Go 1.17, baru saja dirilis, mengambil alih urutan preferensi pasangan cipher untuk semua pengguna Go. Walau Config.CipherSuites masih mengontrol pasangan cipher yang digunakan pada TLS 1.0-1.2, ia tidak digunakan untuk pengurutan, dan Config.PreferServerCipherSuites diindahkan. Paket crypto/tls membuat keputusan pengurutan berdasarkan ketersediaan pasangan cipher, perangkat keras, dan dugaan kapabilitas perangkat keras pada sisi remote. Logika pengurutan TLS 1.0-1.2 yang digunakan sekarang mengikuti aturan-aturan berikut:

  1. ECDHE diprioritaskan dibandingkan pertukaran kunci RSA statis.

    Properti paling penting dari pasangan cipher adalah kerahasiaan. Kita tidak mengimplementasikan Diffie-Hellman "klasik", karena ia kompleks, lambat, lemah, dan rusak pada TLS 1.0-1.2, artinya kita memprioritaskan pertukaran kunci Elliptic Curve Diffie-Hellman dibandingkan pertukaran kunci RSA statis lama. (pertukaran kunci RSA mengenkripsi rahasia koneksi menggunakan kunci publik dari sertifikat, membuatnya bisa didekripsi bila sertifikat bocor di masa depan.)

  2. Mode AEAD lebih prioritas dibandingkan CBC untuk enkripsi.

    Walaupun kita mengimplementasikan penanggulangan untuk Lucky13, kontribusi pertama Vilipo pada pustaka standar di tahun 2015, pasangan CBC sangat sukar diimplementasikan secara benar, sehingga kita memilih AES-GCM dan ChaCha20Poly1305.

  3. 3DES, CBC-SHA256, dan RC4 hanya digunakan bila tidak ada lagi yang tersedia, sesuai dengan urutan tersebut.

    3DES memiliki blok 64-bit, yang membuatnya rentan terhadap serangan birthday bila trafik-nya cukup tinggi. 3DES termasuk ke dalam pasangan cipher tidak aman, namun tetap diaktifkan untuk kompatibilitas. (Salah satu kelebihan dari mengontrol aturan preferensi yaitu kita dapat tetap mengaktifkan pasangan cipher yang tidak aman tanpa perlu khawatir tentang aplikasi atau klien memilihnya kecuali sebagai pilihan terakhir. Hal ini aman karena tidak ada serangan downgrade yang bergantung pada ketersediaan dari pasangan cipher yang lemah untuk menyerang komunikasi yang mendukung alternatif yang lebih baik.)

    Pasangan cipher CBC rentan terhadap serangan Lucky13 side channel dan kita hanya mengimplementasi sebagian dari penanggulangan kompleks seperti yang didiskusikan di atas untuk hash SHA-1, tidak untuk SHA-256. Pasangan CBC-SHA1 memiliki kelebihan kompatibilitas, namun kompleks, dibandingkan CBC-SHA256, sehingga mereka tidak diaktifkan secara bawaan.

    RC4 secara praktik memiliki bias eksploit yang bisa mengakibatkan pembacaan plaintext tanpa side channel. Sehingga RC4 tidak diaktifkan secara bawaan.

  4. ChaCha20Poly1305 diprioritaskan dibandingkan AES-GCM untuk enkripsi, kecuali bila kedua sisi memiliki dukungan perangkat keras.

    Seperti yang kita diskusikan sebelumnya, AES-GCM sangat sukar diimplementasikan secara efisien dan aman tanpa dukungan perangkat keras. Jika kita mendeteksi tidak ada perangkat keras yang mendukung (pada peladen) atau klien tidak memprioritaskan AES-GCM, kita akan memilih ChaCha20Poly1305.

  5. AES-128 is preferred over AES-256 for encryption.

    AES-256 memiliki kunci yang lebih besar dari AES-128, namun melakukan pemanggilan ke lebih banyak fungsi enkripsi, membuatnya lambat. (Tambahan pemanggilan fungsi pada AES-256 bergantung pada ukuran kunci; hal ini untuk menyediakan margin yang lebih luas terhadap cryptanalysis.) Kunci yang besar hanya berguna bila digunakan pada pengaturan dengan banyak user dan post-quantum, yang tidak berhubungan dengan TLS, yang membangkitkan cukup IV acak dan tidak memiliki dukungan pertukaran kunci post-quantum. Secara besar kunci tidak memiliki keuntungan tambahan, kita lebih memilih AES-128 untuk performa lebih cepat.

Logika pengurutan TLS 1.3 hanya membutuhkan dua aturan terakhir, karena TLS 1.3 mengeliminasi algoritma-algoritma bermasalah yang dijaga oleh ketiga aturan pertama di atas.

Pertanyaan yang sering diajukan

Bagaimana bila pasangan cipher ternyata bermasalah? Seperti kerentanan lainnya, ia akan diperbaiki pada rilis keamanan untuk semua versi Go yang didukung. Semua aplikasi harus siap menerapkan perbaikan keamanan supaya beroperasi dengan aman. Secara historis, pasangan cipher yang bermasalah sangat jarang.

Kenapa tetap membuat TLS 1.0-1.2 dapat dikonfigurasi? Ada kelebihan dan kekurangan antara tetap aman dan menjaga kompatibilitas untuk tetap memilih pasangan cipher yang digunakan, dan hal ini merupakan pilihan yang tidak dapat kita lakukan sendiri tanpa meninggalkan sebagian ekosistem atau mengurangi jaminan keamanan bagi pengguna baru.

Kenapa tidak membuat pasangan cipher TLS 1.3 dapat dikonfigurasi? Sebaliknya, tidak ada kelebihan atau kekurangan pada TLS 1.3, karena semua pasangan cipher-nya menyediakan keamanan yang kuat. Hal ini membuat kita dapat mengaktifkan semuanya dan memilih yang tercepat berdasarkan koneksi tertentu tanpa membutuhkan bantuan pengembang.

Poin-poin utama

Mulai dari Go 1.17, crypto/tls mengambil alih urutan pasangan cipher yang dipilih. Dengan secara berkala memperbarui versi Go, hal ini lebih aman daripada membuat klien yang tidak diperbarui memilihnya, membuat kita dapat optimisasi performa, dan mengurangi kompleksitas bagi pengembang Go.

Hal ini konsisten dengan filosofi umum kita yaitu membuat pemilihan kriptografi kapan pun kita mau, bukan mendelegasikannya pada pengembang, dan dengan Prinsip-prinsip kriptografi kita. Semoga pustaka-pustaka TLS lain akan mengadopsi perubahan yang sama, membuat konfigurasi pasangan cipher yang rumit menjadi sejarah di masa lalu.