Interaksi terenkripsi server klien menggunakan Transport Layer Security (TLS) untuk melindungi data aplikasi Anda.
Artikel ini membahas praktik terbaik terkait protokol jaringan yang aman dan pertimbangan Infrastruktur Kunci Publik (PKI). Baca Ringkasan Keamanan Android dan Ringkasan Izin untuk mengetahui detail selengkapnya.
Konsep
Server dengan sertifikat TLS memiliki kunci publik dan kunci pribadi yang cocok. Server menggunakan kriptografi kunci publik untuk menandatangani sertifikatnya selama TLS handshake.
Handshake sederhana hanya membuktikan bahwa server mengetahui kunci pribadi sertifikat. Untuk mengatasi situasi ini, biarkan klien memercayai beberapa sertifikat. Server tertentu tidak dapat dipercaya jika sertifikatnya tidak muncul dalam kumpulan sertifikat tepercaya sisi klien.
Namun, server mungkin menggunakan rotasi kunci untuk mengubah kunci publik sertifikatnya dengan kunci baru. Perubahan konfigurasi server mengharuskan aplikasi klien diupdate. Jika server adalah layanan web pihak ketiga, seperti browser web atau aplikasi email, akan lebih sulit untuk mengetahui kapan harus mengupdate aplikasi klien.
Server biasanya mengandalkan sertifikat Certificate Authorities (CA) untuk menerbitkan sertifikat, yang membuat konfigurasi sisi klien lebih stabil dari waktu ke waktu. CA menandatangani sertifikat server menggunakan kunci pribadinya. Selanjutnya, klien dapat memeriksa apakah server memiliki sertifikat CA yang dikenal oleh platform.
CA tepercaya biasanya tercantum di platform host. Android 8.0 (level API 26) menyertakan lebih dari 100 CA yang diupdate dalam setiap versi dan tidak berubah antar-perangkat.
Aplikasi klien memerlukan mekanisme untuk memverifikasi server karena CA menawarkan sertifikat untuk banyak server. Sertifikat CA mengidentifikasi server menggunakan nama tertentu, seperti gmail.com, atau menggunakan karakter pengganti, seperti *.google.com.
Untuk melihat informasi sertifikat server situs, gunakan perintah
s_client
di alat openssl
dengan meneruskan nomor port. Secara default, HTTPS menggunakan port 443.
Perintah ini mengirimkan output openssl s_client
ke
openssl x509
yang memformat informasi sertifikat dalam
standar X.509. Perintah ini meminta topik (nama server) dan penerbit (CA).
openssl s_client -connect WEBSITE-URL:443 | \ openssl x509 -noout -subject -issuer
Contoh HTTPS
Dengan asumsi bahwa Anda memiliki server web dengan sertifikat yang diterbitkan oleh CA terkenal, Anda dapat membuat permintaan aman seperti yang ditunjukkan dalam kode berikut:
Kotlin
val url = URL("https://wikipedia.org") val urlConnection: URLConnection = url.openConnection() val inputStream: InputStream = urlConnection.getInputStream() copyInputStreamToOutputStream(inputStream, System.out)
Java
URL url = new URL("https://wikipedia.org"); URLConnection urlConnection = url.openConnection(); InputStream in = urlConnection.getInputStream(); copyInputStreamToOutputStream(in, System.out);
Untuk menyesuaikan permintaan HTTP, transmisikan ke HttpURLConnection
.
Dokumentasi HttpURLConnection
Android mencakup
contoh untuk menangani header permintaan dan respons, memublikasikan konten, mengelola cookie, menggunakan
proxy, menyimpan respons dalam cache, dan lainnya. Framework Android memverifikasi sertifikat dan nama host
menggunakan API ini.
Gunakan API ini jika memungkinkan. Bagian berikut membahas masalah umum yang memerlukan solusi berbeda.
Masalah umum dalam memverifikasi sertifikat server
Misalkan getInputStream()
menampilkan pengecualian, bukan menampilkan konten:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374) at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209) at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478) at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433) at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290) at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240) at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282) at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177) at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
Hal ini dapat terjadi karena beberapa alasan, seperti:
- CA yang mengeluarkan sertifikat server tidak dikenal
- Sertifikat server tidak ditandatangani oleh CA, tetapi ditandatangani sendiri.
- CA perantara tidak ditemukan di konfigurasi server.
Bagian berikut membahas cara mengatasi masalah ini sembari menjaga koneksi Anda ke server tetap aman.
Otoritas sertifikat tidak dikenal
SSLHandshakeException
muncul karena sistem tidak memercayai CA. Mungkin ini karena Anda memiliki sertifikat dari
CA baru yang tidak dipercaya oleh Android atau karena aplikasi Anda beroperasi pada versi sebelumnya tanpa
CA. Karena sifatnya pribadi, CA jarang diketahui. Sering kali CA tidak dikenal karena bukan
CA publik, tetapi CA pribadi yang dikeluarkan oleh organisasi seperti pemerintah, perusahaan,
atau institusi pendidikan untuk penggunaan mereka sendiri.
Untuk memercayai CA kustom tanpa perlu mengubah kode aplikasi Anda, ubah Konfigurasi Keamanan Jaringan.
Perhatian:
Banyak situs menjelaskan solusi alternatif yang buruk dengan menginstal
TrustManager
yang tidak berfungsi sama sekali.
Dengan melakukan hal ini, pengguna akan rentan terhadap serangan saat menggunakan hotspot Wi-Fi publik karena
penyerang dapat menggunakan trik DNS untuk mengirimkan traffic pengguna melalui proxy yang berpura-pura
menjadi server Anda. Kemudian penyerang dapat
merekam sandi dan data pribadi lainnya. Cara ini berfungsi karena penyerang dapat membuat
sertifikat, dan tanpa TrustManager
yang memvalidasi bahwa sertifikat tersebut berasal dari sumber
tepercaya, Anda tidak dapat memblokir serangan semacam ini. Jadi, jangan lakukan hal ini, bahkan untuk sementara sekalipun. Sebagai gantinya,
buat aplikasi Anda memercayai penerbit sertifikat server.
Sertifikat server ditandatangani sendiri
Kedua, SSLHandshakeException
dapat terjadi karena sertifikat yang ditandatangani sendiri, membuat server menjadi CA-nya sendiri. Ini serupa dengan certificate authority
yang tidak dikenal, jadi ubah Konfigurasi Keamanan Jaringan aplikasi Anda agar memercayai
sertifikat yang ditandatangani sendiri.
Intermediate certificate authority tidak ada
Ketiga, SSLHandshakeException
terjadi karena CA perantara tidak ada. CA publik jarang menandatangani sertifikat server. Sebaliknya,
CA root menandatangani CA perantara.
Untuk mengurangi risiko penyusupan, CA membuat CA root tetap offline. Namun, sistem operasi seperti Android biasanya hanya memercayai CA root secara langsung sehingga menyisakan sedikit kesenjangan kepercayaan antara sertifikat server—yang ditandatangani CA perantara—dan pemverifikasi sertifikat, yang mengenali CA root.
Untuk menghapus kesenjangan kepercayaan ini, server mengirimkan rantai sertifikat dari CA server melalui perantara apa pun ke CA root tepercaya selama TLS handshake.
Misalnya, berikut adalah rantai sertifikat
mail.google.com seperti yang dilihat oleh perintah s_client
openssl
:
$ openssl s_client -connect mail.google.com:443 --- Certificate chain 0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=mail.google.com i:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA 1 s:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority ---
Rantai sertifikat ini menunjukkan bahwa server mengirimkan sertifikat untuk mail.google.com yang dikeluarkan oleh Thawte SGC CA, yang merupakan CA perantara, dan sertifikat kedua untuk Thawte SGC CA diterbitkan oleh Verisign CA yang merupakan CA utama yang dipercaya oleh Android.
Namun, server mungkin tidak dikonfigurasi untuk menyertakan CA perantara yang diperlukan. Misalnya, berikut adalah server yang dapat menyebabkan kesalahan dalam browser Android dan pengecualian dalam aplikasi Android:
$ openssl s_client -connect egov.uscis.gov:443 --- Certificate chain 0 s:/C=US/ST=District Of Columbia/L=Washington/O=U.S. Department of Homeland Security/OU=United States Citizenship and Immigration Services/OU=Terms of use at www.verisign.com/rpa (c)05/CN=egov.uscis.gov i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 International Server CA - G3 ---
Tidak seperti CA yang tidak dikenal atau sertifikat server yang ditandatangani sendiri, sebagian besar browser desktop tidak menghasilkan error saat berkomunikasi dengan server ini. Cache browser desktop memercayai CA perantara. Setelah mempelajari CA perantara dari satu situs, browser tidak akan membutuhkannya lagi dalam rantai sertifikat.
Beberapa situs sengaja melakukan hal ini untuk server web sekunder penyaluran resource. Untuk menghemat bandwidth, situs-situs itu mungkin menayangkan halaman HTML utama dari server dengan rantai sertifikat lengkap, kecuali gambar, CSS, dan JavaScript tanpa CA. Sayangnya, terkadang server ini dapat menyediakan layanan web yang ingin Anda jangkau dari aplikasi Android, yang tidak terlalu toleran.
Untuk memperbaiki masalah ini, konfigurasi server untuk menyertakan CA perantara dalam rantai server. Sebagian besar CA memberikan petunjuk tentang cara melakukannya untuk server web umum.
Peringatan tentang penggunaan SSLSocket secara langsung
Sejauh ini, contoh berfokus pada HTTPS menggunakan HttpsURLConnection
.
Terkadang aplikasi perlu menggunakan TLS yang terpisah dari HTTPS. Misalnya, aplikasi email mungkin menggunakan varian TLS
dari SMTP, POP3, atau IMAP. Dalam kasus tersebut, aplikasi dapat menggunakan SSLSocket
secara langsung, seperti yang dilakukan HttpsURLConnection
secara internal.
Teknik yang telah dijelaskan sejauh ini
untuk menangani masalah verifikasi sertifikat juga berlaku untuk SSLSocket
.
Bahkan, saat menggunakan TrustManager
kustom, SSLSocketFactory
akan
diteruskan ke HttpsURLConnection
.
Jadi, jika Anda perlu menggunakan TrustManager
kustom beserta
SSLSocket
, ikuti
langkah-langkah yang sama dan gunakan SSLSocketFactory
untuk membuat
SSLSocket
Anda.
Perhatian:
SSLSocket
tidak menjalankan verifikasi nama host. Cara
melakukan verifikasi nama host sendiri bergantung pada aplikasi Anda, tetapi sebaiknya dengan memanggil getDefaultHostnameVerifier()
beserta nama host yang diharapkan.
Selain itu, perhatikan bahwa HostnameVerifier.verify()
tidak menampilkan pengecualian pada error. Sebagai gantinya, metode ini menampilkan hasil boolean yang harus
Anda periksa secara eksplisit.
CA yang diblokir
TLS mengandalkan CA untuk menerbitkan sertifikat, hanya bagi pemilik server dan domain terverifikasi. Dalam kasus yang jarang terjadi, CA dicurangi atau, dalam kasus Comodo atau DigiNotar, dilanggar, sehingga sertifikat untuk nama host dikeluarkan bagi orang lain selain pemilik server atau domain.
Untuk mengurangi risiko ini, Android memiliki kemampuan untuk menambahkan sertifikat tertentu atau bahkan seluruh CA ke daftar tolak. Meskipun daftar ini secara historis dibangun ke dalam sistem operasi, mulai Android 4.2, daftar ini dapat diupdate dari jarak jauh untuk menangani penyusupan di masa mendatang.
Membatasi aplikasi Anda ke sertifikat tertentu
Perhatian: Penyematan sertifikat, yaitu praktik pembatasan sertifikat yang dianggap valid untuk aplikasi Anda ke sertifikat yang telah Anda izinkan sebelumnya, tidak direkomendasikan untuk aplikasi Android. Perubahan konfigurasi server pada masa mendatang, seperti beralih ke CA lain, akan merender aplikasi dengan sertifikat tersemat yang tidak dapat terhubung ke server tanpa menerima update software klien.
Jika Anda ingin membatasi aplikasi agar hanya menerima sertifikat yang ditentukan, Anda harus menyertakan beberapa pin cadangan, termasuk setidaknya satu kunci yang sepenuhnya Anda kendalikan, dan periode habis masa berlaku yang cukup singkat untuk mencegah masalah kompatibilitas. Konfigurasi Keamanan Jaringan menyediakan penyematan dengan kemampuan ini.
Sertifikat klien
Artikel ini berfokus pada penggunaan TLS untuk mengamankan komunikasi dengan server. TLS juga
mendukung konsep sertifikat klien yang memungkinkan server memvalidasi identitas
klien. Meskipun di luar cakupan artikel ini, teknik yang terlibat mirip dengan penetapan
TrustManager
kustom.
Nogotofail: Alat pengujian keamanan traffic jaringan
Nogotofail adalah alat yang memberi Anda kemudahan untuk mengonfirmasi bahwa aplikasi Anda aman terhadap kerentanan dan kesalahan konfigurasi TLS/SSL umum. Inilah alat yang otomatis, kuat, dan skalabel untuk pengujian masalah keamanan jaringan di perangkat apa pun yang dapat dilalui traffic jaringan.
Nogotofail bermanfaat untuk tiga kasus penggunaan utama:
- Menemukan bug dan kerentanan.
- Memverifikasi perbaikan dan memperhatikan regresi.
- Memahami traffic apa yang akan dihasilkan aplikasi dan perangkat.
Nogotofail berfungsi untuk Android, iOS, Linux, Windows, ChromeOS, macOS, dan bahkan perangkat apa pun yang Anda gunakan untuk terhubung ke internet. Klien dapat mengonfigurasi setelan serta mendapatkan notifikasi di Android dan Linux, sedangkan mesin penyerang itu sendiri dapat di-deploy sebagai router, server VPN, atau proxy.
Anda dapat mengakses fitur ini di project open source Nogotofail.
Update untuk SSL dan TLS
Android 10
Beberapa browser, seperti Google Chrome, memungkinkan pengguna untuk memilih sertifikat ketika server TLS mengirimkan
pesan permintaan sertifikat sebagai bagian dari TLS handshake. Mulai Android 10, objek KeyChain mengikuti
parameter spesifikasi kunci dan penerbit saat memanggil KeyChain.choosePrivateKeyAlias()
untuk menampilkan
prompt pemilihan sertifikat kepada pengguna. Secara khusus, prompt ini tidak berisi pilihan yang tidak mematuhi
spesifikasi server.
Jika tidak ada sertifikat yang bisa dipilih pengguna, seperti ketika tidak ada sertifikat yang cocok dengan spesifikasi server atau perangkat tidak memiliki sertifikat yang terinstal, prompt pemilihan sertifikat tidak akan muncul.
Selain itu, di Android 10 atau yang lebih tinggi, Anda tidak harus menyetel kunci layar perangkat untuk mengimpor kunci atau sertifikat CA ke objek KeyChain.
TLS 1.3 diaktifkan secara default
Di Android 10 dan yang lebih tinggi, TLS 1.3 diaktifkan secara default untuk semua koneksi TLS. Berikut adalah beberapa detail penting tentang implementasi TLS 1.3 kami:
- Cipher suite TLS 1.3 tidak bisa disesuaikan. Cipher suite TLS 1.3 yang didukung selalu
diaktifkan saat TLS 1.3 diaktifkan. Upaya apa pun untuk menonaktifkannya dengan memanggil
setEnabledCipherSuites()
akan diabaikan. - Saat TLS 1.3 dinegosiasikan, objek
HandshakeCompletedListener
akan dipanggil sebelum sesi ditambahkan ke cache sesi. (Pada TLS 1.2 dan versi sebelumnya, objek ini dipanggil setelah sesi ditambahkan ke cache sesi.) - Dalam beberapa situasi saat instance SSLEngine menampilkan
SSLHandshakeException
di versi Android sebelumnya, instance ini akan menampilkanSSLProtocolException
di Android 10 dan yang lebih tinggi. - Mode 0-RTT tidak didukung.
Jika diinginkan, Anda bisa mendapatkan SSLContext yang menonaktifkan TLS 1.3 dengan memanggil
SSLContext.getInstance("TLSv1.2")
. Anda juga dapat mengaktifkan atau menonaktifkan versi protokol berbasis per koneksi dengan memanggil setEnabledProtocols()
di objek yang sesuai.
Sertifikat yang ditandatangani dengan SHA-1 tidak dipercaya di TLS
Di Android 10, sertifikat yang menggunakan algoritma hash SHA-1 tidak dipercaya dalam koneksi TLS. CA root belum menerbitkan sertifikat seperti itu sejak 2016, dan sertifikat tersebut tidak lagi dipercaya di Chrome atau browser utama lainnya.
Setiap upaya untuk terhubung akan gagal jika koneksi dibuat ke situs yang menyajikan sertifikat yang menggunakan SHA-1.
Perubahan dan peningkatan perilaku KeyChain
Beberapa browser seperti Google Chrome memungkinkan pengguna untuk memilih sertifikat ketika server TLS mengirimkan
pesan permintaan sertifikat sebagai bagian dari TLS handshake. Mulai Android 10,
objek KeyChain
mematuhi
penerbit dan parameter spesifikasi utama saat memanggil KeyChain.choosePrivateKeyAlias()
untuk menampilkan
prompt pemilihan sertifikat kepada pengguna. Secara khusus, prompt ini tidak berisi pilihan yang tidak
mematuhi spesifikasi server.
Jika tidak ada sertifikat yang bisa dipilih pengguna, seperti ketika tidak ada sertifikat yang cocok dengan spesifikasi server atau perangkat tidak memiliki sertifikat yang terinstal, prompt pemilihan sertifikat tidak akan muncul.
Selain itu, di Android 10 atau yang lebih tinggi, Anda tidak harus menyetel kunci layar perangkat untuk mengimpor kunci atau sertifikat CA ke objek KeyChain.
Perubahan TLS dan kriptografi lainnya
Ada beberapa perubahan kecil dalam library TLS dan kriptografi yang diberlakukan di Android 10:
- Cipher AES/GCM/NoPadding dan ChaCha20/Poly1305/NoPadding menampilkan ukuran buffer yang lebih akurat
dari
getOutputSize()
. - Cipher suite TLS_FALLBACK_SCSV dihilangkan dari upaya koneksi dengan protokol maksimum TLS 1.2 atau yang lebih baru. Dengan diterapkannya peningkatan di server TLS, sebaiknya Anda tidak mencoba penggantian TLS eksternal. Sebagai gantinya, cobalah untuk mengandalkan negosiasi versi TLS.
- ChaCha20-Poly1305 adalah alias untuk ChaCha20/Poly1305/NoPadding.
- Nama host yang memiliki titik akhir tidak dianggap sebagai nama host SNI yang valid.
- Ekstensi supported_signature_algorithms dalam CertificateRequest dipatuhi ketika memilih kunci penandatanganan untuk respons sertifikat.
- Kunci penandatanganan dengan akses terbatas, seperti yang berasal dari Android Keystore, dapat digunakan dengan tanda tangan RSA-PSS di TLS.
Perubahan koneksi HTTPS
Jika aplikasi yang menjalankan Android 10 meneruskan null ke setSSLSocketFactory()
, IllegalArgumentException
akan terjadi. Pada versi sebelumnya, meneruskan null ke setSSLSocketFactory()
memiliki efek yang sama dengan meneruskan nilai default pabrik yang aktif.
Android 11
Soket SSL menggunakan mesin SSL Conscrypt secara default
Implementasi SSLSocket default Android didasarkan pada Conscrypt
. Mulai Android 11, implementasi tersebut dikembangkan secara internal di atas SSLEngine Conscrypt.