Server SSH adalah pintu paling ramai digodok di internet: begitu sebuah alamat IP membuka port 22, bot mulai mencoba login dengan daftar password favorit dunia — terus-menerus, siang malam, tanpa bosan. Konfigurasi bawaan sshd memang mengutamakan kemudahan, bukan ketahanan: login password diperbolehkan dan root boleh dicoba. Chapter ini mengunci pintu itu selangkah demi selangkah: berpindah ke SSH key, melarang password, membatasi user dan percobaan, lalu menyerahkan pencobaan yang bandul kepada fail2ban. Karena mesin latihan kita tidak menjalankan sshd, konfigurasi kita tulis sebagai file latihan yang strukturnya sama dengan yang asli, sementara perintah sistem sungguhan ditampilkan sebagai panduan.

Ancaman: Brute Force Password #

Serangan paling murah terhadap SSH adalah menebak: coba root dengan 123456, coba admin dengan password, ulangi ribuan kali. Jejaknya terekam rapi di log autentikasi — /var/log/auth.log pada keluarga Debian, atau journal untuk sistem yang mengarah lognya ke journald. Berikut contoh tampilan tiga baris log pada server yang sedang digodok:

text
Feb 12 03:14:07 server-kantor sshd[2841]: Failed password for root from 203.0.113.45 port 51234 ssh2
Feb 12 03:14:11 server-kantor sshd[2841]: Failed password for root from 203.0.113.45 port 51235 ssh2
Feb 12 03:14:15 server-kantor sshd[2842]: Failed password for invalid user admin from 203.0.113.45 port 51236 ssh2

Tiga baris dalam delapan detik itu pola khas bot: nama user umum dicoba berurutan dari alamat yang sama. Menebak password lewat jaringan seperti ini disebut brute force, dan pertahanan terhadapnya berlapis tiga — password yang panjang (dibahas pada Chapter Authentication Basics ), pembatasan percobaan, dan yang paling ampuh: memindahkan pintu ke mekanisme yang tidak bisa ditebak sama sekali.

SSH Key: Identitas yang Tidak Bisa Ditebak #

SSH key mengganti “sesuatu yang kita tahu” dengan “sesuatu yang kita miliki”. Kita membuat sepasang kunci: kunci privat tinggal di laptop kita dan tidak boleh kemana-mana, kunci publik bebas disalin ke server mana pun. Server lalu menantang kita membuktikan kepemilikan kunci privat lewat operasi matematika — tanpa pernah menerima password, sehingga tidak ada yang bisa ditebak. Pembuatannya satu perintah; berikut contoh tampilan sesi lengkapnya:

console
$ ssh-keygen -t ed25519 -C "budi@laptop-budi"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/budi/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/budi/.ssh/id_ed25519
Your public key has been saved in /home/budi/.ssh/id_ed25519.pub

Opsi -t ed25519 memilih algoritma ed25519 — kunci pendek dan cepat yang jadi rekomendasi saat ini — dan -C hanya memberi komentar agar kunci mudah dikenali. Passphrase melindungi kunci privat bila file-nya dicuri; laptop yang sering dibawa-bawa sebaiknya mengisinya. Isi file .pub adalah satu baris: jenis kunci, kuncinya, lalu komentar:

text
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGh5nK9mQ2wR7tY1uIoP9aS3dF6hG4jK0mN8bVcXzQ1eW3 budi@laptop-budi

Di sisi server, kunci publik itu ditempelkan ke file ~/.ssh/authorized_keys — biasanya oleh ssh-copy-id, tetapi menempelkannya manual sama sahnya. Persyaratan yang sering menggagalkan pemula adalah permission foldernya: sshd menolak kunci bila ~/.ssh terlalu terbuka. Kita latih urutannya:

bash
mkdir -p .ssh
printf 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGh5nK9mQ2wR7tY1uIoP9aS3dF6hG4jK0mN8bVcXzQ1eW3 budi@laptop-budi\n' > .ssh/authorized_keys
chmod 700 .ssh
chmod 600 .ssh/authorized_keys
stat -c '%a %n' .ssh .ssh/authorized_keys

Output yang Dihasilkan:

text
700 .ssh
600 .ssh/authorized_keys

Mari kita bedah blok di atas:

  1. Baris 1 (mkdir -p .ssh): membuat folder kunci bila belum ada; opsi -p membuat perintah aman diulang.
  2. Baris 2 (printf ... > .ssh/authorized_keys): menempelkan kunci publik contoh ke daftar kunci yang diterima. Formatnya selalu satu kunci per baris, jadi menambah user lain berarti menambah baris baru.
  3. Baris 3-4 (chmod 700 dan chmod 600): folder hanya boleh dimasuki owner (700), dan daftar kunci hanya boleh dibaca owner (600) — sshd memang menolak berlaku baik pada file yang bisa ditulis orang lain.
  4. Baris 5 (stat -c '%a %n'): memverifikasi hasil akhirnya. Angka 700 dan 600 itulah yang harus terlihat; bila muncul angka lain, login key akan gagal diam-diam.

Enam Arahan Inti sshd_config #

Konfigurasi sshd terpusat di /etc/ssh/sshd_config. Mesin latihan kita tidak menjalankan sshd, jadi kita tulis versi latihan berisi enam arahan yang menjadi inti hardening:

bash
printf 'Port 2222\nPermitRootLogin no\nPasswordAuthentication no\nPubkeyAuthentication yes\nMaxAuthTries 3\nAllowUsers budi\n' > sshd_config
cat sshd_config

Output yang Dihasilkan:

text
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers budi

Enam baris di atas satu per satu:

  1. Port 2222: sshd berhenti mendengarkan di port 22 dan pindah ke 2222. Kita bahas kejujurannya di bagian berikutnya.
  2. PermitRootLogin no: akun root sama sekali tidak boleh login lewat SSH. Root memang terlalu berharga untuk digodok langsung; admin yang butuh hak tinggi login sebagai user biasa lalu naik lewat sudo — jejaknya pun tercatat atas nama orangnya.
  3. PasswordAuthentication no: arahan paling berdampak — menebak password jadi mustahil karena password tidak lagi diterima. Login hanya lewat kunci.
  4. PubkeyAuthentication yes: penegasan pasangan arahan sebelumnya. Nilai bakunya memang yes, tetapi menuliskannya eksplisit membuat konfigurasi tetap benar meski ada drop-in lain yang mencoba menimpanya.
  5. MaxAuthTries 3: membatasi percobaan autentikasi per koneksi. Bila tiga kali gagal, koneksi diputus — bot harus membuka koneksi baru, dan itu persis yang dipantau fail2ban.
  6. AllowUsers budi: hanya user yang tercantum boleh login lewat SSH. User lain — termasuk akun service yang tanpa sengaja aktif — tertutup rapat meskipun passwordnya benar. Bentuk kerabatnya AllowGroups bekerja berbasis group.

Penerapan di sistem sungguhan selalu tiga langkah: ubah /etc/ssh/sshd_config dengan editor, uji sintaksnya dengan sudo sshd -t yang tidak mencetak apa pun bila konfigurasi sehat, lalu muat ulang dengan sudo systemctl reload sshd. Untuk mengaudit nilai efektif yang sebenarnya dipakai sshd — termasuk nilai baku yang tidak tertulis di file — perintah sudo sshd -T menampilkan seluruhnya; menyaringnya dengan grep -i passwordauthentication langsung menjawab “pintu password sudah tertutup rapat atau belum”.

Mengubah Port: Obscurity yang Jujur #

Pindah ke port 2222 memang memotong hampir seluruh lalu lintas bot dari log — bot pemindai massal hanya menyentuh port standar. Tetapi mari jujur: ini bukan security yang sesungguhnya. Pemindai menyasar seluruh port akan menemukan sshd di 2222 dalam hitungan detik, dan versi SSH-nya pun bisa disamarkan. Jadi port berfungsi sebagai peredam kebisingan, bukan tembok. Dua syarat bila kita memakainya: buka dulu port baru di firewall sebelum reload sshd, dan pastikan aturan Port di sshd_config serta konfigurasi fail2ban menunjuk port yang sama.

fail2ban: Menutup Bot secara Otomatis #

fail2ban memantau log secara terus-menerus dengan pola regex; ketika satu alamat IP gagal login terlalu sering dalam jangka waktu tertentu, fail2ban menambahkan aturan firewall yang memblokir alamat itu untuk sementara. Satu “penjara” (jail) didefinisikan per service yang dipantau, dan seluruh penyetelannya ditulis di jail.local — salinan penimpa agar file bawaan jail.conf tetap bersih saat paket diperbarui. Karena jail milik kita harus cocok dengan arahan sshd tadi, beginilah wujud latihannya:

bash
printf '[sshd]\nenabled = true\nport = 2222\nmaxretry = 5\nfindtime = 10m\nbantime = 1h\n' > jail.local
cat jail.local

Output yang Dihasilkan:

text
[sshd]
enabled = true
port = 2222
maxretry = 5
findtime = 10m
bantime = 1h

Baris per baris, penjara di atas berbunyi:

  1. [sshd]: nama penjara — fail2ban mengenali service apa yang lognya dibaca dari nama ini.
  2. enabled = true: menyalakan penjara; banyak penjara bawaan mati secara default dan menunggu baris ini.
  3. port = 2222: port yang dijaga — sama persis dengan arahan Port pada sshd_config kita, karena alamat yang diblokir harus mengenai port yang benar.
  4. maxretry = 5: batas gagal dalam satu jendela waktu sebelum ban dijatuhkan.
  5. findtime = 10m: lebar jendela waktu itu — lima kegagalan dalam sepuluh menit memicu ban.
  6. bantime = 1h: lama alamat diblokir. Durasi satu jam sudah cukup untuk membuat bot penyerang murah pindah target, tanpa menghukum manusia yang salah ketik passwordnya sendiri.

Dengan kombinasi kunci, larangan password, dan fail2ban, pintu SSH kini memeriksa identitas dan tempo percobaan. Namun semua itu masih bicara tentang satu pintu — belum ada kebijakan tentang lalu lintas jaringan secara keseluruhan. Tugas itulah pekerjaan firewall, chapter berikutnya.

Referensi lanjut: manual resmi OpenSSH untuk seluruh halaman manual sshd dan kawan-kawannya, sshd_config(5) untuk daftar lengkap arahannya, ssh-keygen(1) untuk opsi pembuatan kunci, serta wiki Arch Linux tentang fail2ban untuk contoh penjara lanjutan.