Bali, Indonesia
Insights

Mengira SSL Sudah Benar karena Chrome Aman, Padahal Intermediate Belum Dipasang

November 4, 2026
0:00
Banyak dari kita menganggap pemasangan SSL sudah beres begitu gembok muncul di Chrome. Beberapa hari kemudian tim mobile melapor aplikasi Android gagal konek ke API, atau skrip curl dari server lain keluar error unable to verify the first certificate. Sertifikatnya belum kedaluwarsa dan nama domainnya cocok, tapi koneksinya tetap ditolak. Penyebab yang paling sering bukan sertifikatnya, melainkan intermediate certificate yang tidak ikut dikirim oleh server. Asumsi bahwa browser desktop adalah alat uji yang cukup kelihatannya masuk akal, karena browser adalah client yang paling sering kita pakai. Masalahnya, browser modern justru termasuk client yang paling toleran terhadap konfigurasi yang kurang lengkap.
Sertifikat SSL bekerja sebagai rantai, atau chain. Sertifikat domain kamu (sering disebut leaf certificate) ditandatangani oleh intermediate certificate milik certificate authority (CA). Intermediate itu ditandatangani oleh root certificate. Root inilah yang tersimpan di trust store, yaitu daftar CA tepercaya yang dibawa oleh sistem operasi, browser, atau runtime bahasa pemrograman. Intermediate biasanya tidak ada di trust store. Karena itu, server seharusnya mengirim leaf dan intermediate sekaligus saat TLS handshake, supaya client bisa menyusun jalur dari sertifikat domain sampai ke root yang ia percaya. Kalau server hanya mengirim leaf, ada satu mata rantai yang hilang. Di titik inilah browser sering menutupi masalah. Leaf certificate umumnya punya field Authority Information Access (AIA) yang berisi URL tempat intermediate bisa diunduh. Chrome di banyak platform akan mengikuti URL itu dan mengambil intermediate sendiri, sebuah mekanisme yang disebut AIA fetching. Browser juga bisa menyimpan intermediate yang pernah ia lihat saat membuka situs lain yang memakai CA sama. Firefox memakai pendekatan berbeda: ia membawa daftar intermediate yang sudah dikenal. Hasil akhirnya mirip. Chain di server bolong, tapi browser tetap berhasil menyusunnya. Jadi gembok di Chrome sebenarnya menguji kemampuan browser memperbaiki chain, bukan kebenaran konfigurasi server. Ini juga kasus yang berbeda dari gembok yang hilang karena resource dimuat lewat http://. Untuk kasus itu, bacaannya ada di Gembok HTTPS Tidak Muncul Padahal SSL Sudah Terpasang? Cek Mixed Content.
Di luar browser, kebanyakan client tidak melakukan AIA fetching. Mereka hanya memakai apa yang dikirim server ditambah isi trust store lokal. Kalau intermediate tidak dikirim, verifikasi gagal. Yang biasanya termasuk kelompok ini adalah curl, library berbasis OpenSSL, Python requests, Node.js, Java, banyak aplikasi Android yang memakai TLS stack bawaan platform, layanan monitoring uptime, dan sistem pihak ketiga yang mengirim webhook ke server kamu. Pesan errornya beragam. OpenSSL dan Node.js biasanya menampilkan unable to verify the first certificate. curl dengan backend OpenSSL umumnya menampilkan SSL certificate problem: unable to get local issuer certificate. Java biasanya melempar PKIX path building failed. Dampak di production sering lebih terasa daripada yang terlihat di awal. Halaman web normal, jadi tidak ada yang curiga. Sementara itu notifikasi payment gateway tidak sampai, aplikasi mobile gagal login, dan integrasi API antar server putus. Di meja support, kalimat yang sering muncul adalah: di browser aman kok, berarti masalahnya di aplikasi. Padahal hal pertama yang layak dicek justru chain yang dikirim server.
Cara paling langsung adalah meminta server menunjukkan apa yang benar-benar ia kirim. Jalankan perintah ini dari terminal, sebaiknya dari mesin selain laptop yang dipakai browsing:
BASH
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
Opsi -servername mengirim SNI, yaitu nama host yang diminta client. Opsi ini penting di server yang melayani banyak domain di satu IP, supaya kamu melihat sertifikat untuk domain yang benar. -showcerts menampilkan semua sertifikat yang dikirim server, dan </dev/null membuat perintah langsung selesai setelah handshake. Bagian yang perlu dibaca adalah Certificate chain dan baris Verify return code di bagian bawah. Ini contoh format output untuk chain yang tidak lengkap:
TEXT
Certificate chain
 0 s:CN = example.com
   i:C = XX, O = Contoh CA, CN = Contoh Intermediate CA
---
...
Verify return code: 21 (unable to verify the first certificate)
Baris s: adalah subject, yaitu sertifikat milik siapa. Baris i: adalah issuer, yaitu siapa yang menandatanganinya. Pada contoh ini hanya ada entri nomor 0, yaitu leaf. Issuer-nya adalah sebuah intermediate, tapi intermediate itu tidak muncul sebagai entri nomor 1. Itu tanda chain-nya bolong. Pada chain yang lengkap, entri nomor 1 punya subject yang sama persis dengan issuer entri nomor 0, dan Verify return code bernilai 0 (ok). Perlu dicatat, s_client memakai trust store default sesuai cara OpenSSL di-build. Kalau semua domain menghasilkan error verifikasi, termasuk domain yang jelas sehat, kemungkinan trust store-nya yang tidak ditemukan. Di kasus seperti itu kamu bisa menunjuk file CA bundle sistem dengan opsi -CAfile, dan lokasinya berbeda per distro. Untuk cek cepat dari sisi client, curl -sv https://example.com -o /dev/null juga cukup. Kalau curl gagal di verifikasi sementara browser lancar, hampir pasti masalahnya ada di chain.
Intermediate biasanya ikut dikirim oleh CA bersama sertifikat domain, sering dalam file bernama CA bundle, chain, atau ca-bundle. Jangan asal mengambil intermediate dari situs lain atau hasil pencarian. CA bisa punya beberapa intermediate, dan yang dipasang harus yang benar-benar menandatangani sertifikat kamu. Cara memastikannya adalah mencocokkan issuer leaf dengan subject intermediate:
BASH
# Issuer milik sertifikat domain harus sama dengan subject intermediate
openssl x509 -in domain.crt -noout -subject -issuer
openssl x509 -in intermediate.crt -noout -subject

# Gabungkan dengan urutan leaf dulu, lalu intermediate
cat domain.crt intermediate.crt > fullchain.crt
Urutannya penting: leaf di paling atas, lalu intermediate di bawahnya. Root tidak perlu disertakan, karena client sudah memilikinya di trust store. Setelah menggabungkan file, buka hasilnya dan pastikan baris -----END CERTIFICATE----- dan -----BEGIN CERTIFICATE----- tidak menempel di satu baris. Hal ini bisa terjadi kalau file pertama tidak diakhiri newline. Cara pasangnya tergantung web server dan panel yang dipakai:
  • cPanel/WHM: form instalasi SSL biasanya punya kolom terpisah untuk CA bundle. Kalau kolom itu dikosongkan, server hanya mengirim leaf. Nama kolomnya bisa sedikit berbeda antar versi.
  • Nginx: tidak punya direktif khusus untuk chain. ssl_certificate harus menunjuk ke file gabungan, misalnya ssl_certificate /path/ke/fullchain.crt;. Jalankan nginx -t sebelum reload.
  • Apache: mulai 2.4.8, SSLCertificateFile bisa berisi leaf beserta chain. Konfigurasi lama memakai SSLCertificateChainFile yang terpisah. Cek konfigurasi dengan apachectl configtest.
  • Certbot: Certbot membuat cert.pem (leaf saja) dan fullchain.pem (leaf beserta intermediate). Kesalahan yang sering terjadi adalah memakai cert.pem di konfigurasi web server, padahal seharusnya fullchain.pem.
  • LiteSpeed: pengaturan chain tergantung versi dan apakah dikelola lewat panel atau WebAdmin. Cek dokumentasi untuk setup yang kamu pakai.
Setelah reload, jalankan lagi perintah s_client tadi dan pastikan entri nomor 1 muncul dan return code-nya 0 (ok).
Aturan praktisnya sederhana: verifikasi SSL dari client yang paling tidak toleran, bukan dari yang paling toleran. Jadikan s_client atau curl dari server lain sebagai langkah wajib setiap kali memasang, mengganti, atau memperpanjang sertifikat. Perpanjangan perlu diperhatikan khusus. Waktu memperbarui sertifikat, CA kadang menerbitkannya dari intermediate yang berbeda dengan sebelumnya. Kalau yang diganti hanya file leaf sementara file intermediate lama dibiarkan, chain-nya bisa salah walaupun semua file ada di tempatnya. Kalau perpanjangan otomatis lewat AutoSSL sendiri gagal, itu masalah yang berbeda dan dibahas di Kenapa AutoSSL Gagal Diperbarui Padahal Domain Sudah Mengarah ke Server. Kalau ada sistem monitoring, tambahkan pengecekan TLS dari client non-browser yang memeriksa hasil verifikasi, bukan hanya tanggal kedaluwarsa. Dengan begitu chain yang bolong ketahuan sebelum integrasi pihak ketiga mulai gagal. Intinya, gembok di Chrome hanya memberi tahu bahwa browser berhasil menyusun chain, entah dari server atau dari usahanya sendiri. Yang perlu kita pastikan adalah server mengirim leaf dan intermediate yang tepat dengan urutan yang benar. Satu perintah openssl s_client sudah cukup untuk menjawabnya, jadi biasakan menjalankannya setiap kali menyentuh sertifikat.