6 poin oleh GN⁺ 2023-08-24 | 1 komentar | Bagikan ke WhatsApp
  • SSH adalah alat yang mencakup lebih dari sekadar akses jarak jauh: port forwarding, jump host, file konfigurasi, hingga manajemen kunci, dan contoh server web di sini bisa langsung diterapkan juga ke layanan lain seperti RDP dan SQL
  • Port forwarding lokal, jarak jauh, dan dinamis masing-masing menggunakan -L, -R, dan -D, dengan perbedaan utama pada sisi mana port dibuka dan ke mana trafik mengalir
  • Pada jaringan yang memblokir akses langsung, jump host -J dan ProxyJump dapat merangkai beberapa perantara SSH untuk mencapai tujuan
  • ssh-agent dan agent forwarding -A memungkinkan penggunaan kunci lokal juga di host jarak jauh, tetapi risiko keamanan akibat penyalahgunaan agent harus dipahami terlebih dahulu
  • Dengan memakai ~/.ssh/config, ssh-copy-id, ssh-keygen, serta konsol SSH ~? dan ~C bersama-sama, kita bisa mengurangi input opsi berulang, menambah forwarding saat sesi berjalan, mempermudah distribusi kunci publik, serta pembuatan dan pemeriksaan kunci

Prasyarat untuk memahami SSH port forwarding

  • Alur SSH port forwarding sulit dipahami hanya dari diagram, sehingga lebih mudah dimengerti bila melihat perintah nyata beserta skenario jaringannya
  • Contoh menggunakan akses ke server web, tetapi cara yang sama juga berlaku untuk hampir semua layanan seperti RDP, SQL, dan lainnya
  • Opsi yang sering dipakai berulang memiliki arti berikut
    • -N: tidak menjalankan perintah di server jarak jauh dan juga tidak membuka shell
    • -f: menjalankan SSH di background
    • root@host: login ke pengguna dan host yang akan dipakai untuk membuat tunnel

Local port forwarding -L

  • Local port forwarding meneruskan port pada mesin lokal ke port pada server jarak jauh
  • Contoh situasi
    • internal-web.int meng-host halaman web yang hanya dapat diakses dari interface loopback
    • campfire.int dapat mengakses internal-web.int melalui SSH
    • Ingin mengakses server web di internal-web.int melalui port lokal milik campfire.int
  • Perintah yang digunakan
    • ssh -N -f -L 1337:127.0.0.1:80 root@internal-web.int
  • Penjelasan opsi
    • -L: menentukan local forwarding
    • 1337:127.0.0.1:80: mengikat port lokal 1337 ke 127.0.0.1:80 di sisi jarak jauh
  • Setelah tunnel dibuat, kita bisa mengirim permintaan ke port lokal 1337 dari campfire.int untuk berinteraksi dengan port 80 milik internal-web.int
  • Hal yang perlu diingat adalah pada -L, port lokal berada di sisi kiri alamat

Remote port forwarding -R

  • Remote port forwarding mengekspos port yang dapat diakses dari lokal ke port pada server jarak jauh
  • Contoh situasi
    • internal-web.int meng-host halaman web yang hanya bisa diakses melalui loopback
    • campfire.int tidak bisa langsung mengakses internal-web.int karena firewall
    • vuln-server.int dapat diakses dari campfire.int maupun internal-web.int
  • Perintah yang digunakan
    • ssh -N -f -R 3000:127.0.0.1:80 root@vuln-server.int
  • Penjelasan opsi
    • -R: menentukan remote forwarding
    • 3000:127.0.0.1:80: mengikat port 3000 di vuln-server.int ke 127.0.0.1:80 di lokal
  • Setelah itu, jika mengirim permintaan curl ke vuln-server.int:3000, kita dapat mengakses halaman web internal yang berjalan di port 80 milik internal-web.int
  • Hal yang perlu diingat adalah pada -R, port lokal berada di sisi kanan alamat

Dynamic port forwarding -D dan proxy SOCKS

  • Dynamic port forwarding membuat proxy SOCKS dengan opsi -D dan mengirim trafik melalui perantara SSH
  • Contoh situasi
    • internal-web.int meng-host aplikasi web yang hanya dapat diakses dari jaringan internal
    • vuln-server.int berada di jaringan internal yang sama dan dapat mengakses internal-web.int
    • Ingin mem-proxy trafik dari campfire.int melalui vuln-server.int
  • Konfigurasi /etc/proxychains.conf harus sesuai dengan port pada perintah SSH
    • socks5: membuat proxychains menggunakan SOCKS5
    • 127.0.0.1: menggunakan localhost
    • 8080: harus sama dengan port yang ditentukan pada SSH -D
  • Perintah yang digunakan
    • ssh -N -f -D 8080 root@vuln-server.int
  • Setelah forwarding dibuat, jika socks5 127.0.0.1 8080 dikonfigurasi, kita bisa mengakses halaman web internal dengan proxychains curl 192.168.1.185
  • DNS melalui SOCKS kadang tidak berjalan baik tergantung lingkungan, sehingga pada contoh digunakan alamat IP alih-alih nama host
  • Di Firefox juga bisa memakai proxy SOCKS lewat konfigurasi proxy manual
    • Jalur: Settings → Privacy & Security → Network Settings
    • Pilih Manual proxy configuration
    • Centang “Proxy DNS when using SOCKS V5”
    • Atur SOCKS host ke 127.0.0.1 dan port ke 8080

Jump host -J

  • Jump host memungkinkan koneksi ke tujuan yang tidak bisa diakses langsung dari host saat ini dengan melewati beberapa perantara SSH
  • Rantai contoh adalah campfire.intvuln-server.intinternal-web.intdns.int
  • Perintah yang digunakan
    • ssh -J root@vuln-server.int,root@internal-web.int root@dns.int
  • Beberapa target lompatan dipisahkan dengan koma

Agent forwarding -A

  • ssh-agent memungkinkan penambahan private key atau ID di mesin lokal dengan ssh-add <private_key_file>
  • Kunci yang ditambahkan bisa dilihat dengan ssh-add -l
  • Dengan menambahkan kunci ke ssh-agent, kita bisa melakukan koneksi SSH menggunakan kunci tersebut tanpa perlu memasukkan kata sandi lagi, sehingga berguna baik untuk manusia maupun akun layanan
  • Agent forwarding -A memungkinkan penggunaan kunci dari agent lokal juga di mesin jarak jauh yang kita masuki
  • Untuk memeriksa risiko keamanannya sebelum digunakan, lihat Zero Effort Private Key Compromise: Abusing SSH-Agent for Lateral Movement
  • Contoh perintah
    • ssh -A -J root@vuln-server.int root@internal-web.int
  • Perintah ini terhubung ke internal-web.int melalui vuln-server.int sambil memungkinkan penggunaan kunci yang ada di SSH agent lokal campfire.int
  • Setelah itu, saat menjalankan ssh root@dns.int dari internal-web.int, kita bisa terhubung tanpa menentukan private key atau memasukkan kredensial

Alokasi perintah TTY -t

  • Opsi -t berguna untuk cepat menjalankan perintah yang memerlukan interaksi di server jarak jauh
  • Contohnya adalah perintah yang membutuhkan TTY seperti Vim atau top
  • Perintah yang digunakan
    • ssh root@internal-web.int -t top
  • Saat dijalankan, kita akan mendapat TTY di server jarak jauh beserta perintah top

Membuat host eksternal juga bisa terhubung ke port local forwarding dengan -g

  • Opsi -g memungkinkan host jarak jauh terhubung ke port yang di-forward secara lokal
  • Mirip dengan local port forwarding -L, tetapi bedanya mesin eksternal juga bisa memakai port “lokal” tersebut
  • Contoh situasi
    • Ada akses shell ke vuln-server.int
    • Ingin mem-proxy koneksi yang masuk ke port 2222 di vuln-server.int ke port 22 di internal-web.int
  • Perintah yang digunakan
    • ssh -N -f -g -L 2222:localhost:22 root@internal-web.int
  • Penjelasan opsi
    • -g: memungkinkan host jarak jauh terhubung ke port local forwarding
    • -L: menentukan local forwarding
  • Meski terhubung via SSH ke port 2222 di vuln-server.int, shell yang sebenarnya akan berada di internal-web.int

Konsol SSH ~? dan forwarding di tengah sesi

  • Konsol SSH adalah fitur tersembunyi yang memungkinkan kita mengontrol SSH itu sendiri tanpa berinteraksi langsung dengan sistem jarak jauh
  • Fitur ini berguna saat shell rusak atau ketika kita perlu mengendalikan sesi SSH itu sendiri
  • Konsol bantuan dapat dibuka dengan ~?
  • Opsi yang berguna
    • ~.: menutup sesi SSH saat ini
    • ~C: membuka konsol SSH untuk menambahkan opsi forwarding
  • Bahkan setelah sudah terhubung ke vuln-server.int dengan perintah ssh biasa, kita bisa menekan ~C lalu memasukkan -D 8080 agar sesi tersebut dipakai seperti sesi dynamic forwarding
  • Jika /etc/proxychains.conf di campfire.int disetel memakai port 8080, maka proxychains bisa digunakan seolah-olah sesi dimulai sejak awal dengan ssh -D

File konfigurasi SSH ~/.ssh/config

  • File konfigurasi SSH berada di ~/.ssh/config dan memungkinkan kita menyimpan opsi SSH yang sering diketik ulang untuk menghemat waktu
  • Saat melakukan koneksi SSH, file ini diparse, dan bila ada pengaturan host yang cocok dengan target koneksi, opsi tersebut akan digunakan
  • Argumen command line memiliki prioritas lebih tinggi daripada file konfigurasi
    • Misalnya, walaupun file konfigurasi menetapkan pengguna root untuk internal-web.int, menjalankan ssh graham@internal-web.int akan mencoba login sebagai graham
  • Contoh konfigurasi dasar
# You can put comments with a `#` at the beginning of the line only.
host internal-web.int
    User root
    IdentityFile /home/smores/ssh_agent/internal-web-no-pw
    Port 2222
  • Alur pemrosesan saat menjalankan ssh internal-web.int
    • Mencocokkan internal-web.int pada command line dengan host internal-web.int di ~/.ssh/config
    • Jika cocok, mengambil opsi yang tidak ditentukan di command line dari file konfigurasi
    • Jika tidak cocok, hanya menggunakan opsi yang didefinisikan di command line

Kata kunci SSH config yang sering dipakai

  • IdentityFile /path/to/private_key
    • Menentukan private key yang akan dipakai untuk host
    • Fungsinya sama dengan ssh -i
  • ForwardAgent
  • ProxyJump root@internal-web.int
    • Menentukan server yang akan dipakai untuk mem-proxy trafik
    • Fungsinya sama dengan opsi -J
    • Dalam contoh, ini menunjukkan bahwa trafik melewati host tersebut karena autentikasi vuln-server.int diminta lebih dulu
  • Match
    • Menerapkan kata kunci SSH config berdasarkan kondisi tertentu
    • Dalam contoh, jika exit code dari perintah export | grep PROXYME=TRUE adalah 0, maka ProxyJump di bawah blok Match akan digunakan
    • Jika variabel lingkungan PROXYME tidak ada, hanya blok host internal-web.int biasa yang akan digunakan
    • Setelah mengatur export PROXYME=TRUE, menjalankan ssh internal-web.int yang sama akan melewati autentikasi vuln-server.int lalu memberikan shell internal-web.int
  • scp dan beberapa utilitas berbasis SSH lainnya biasanya juga dapat memakai SSH config
    • Di lingkungan yang tidak memakainya secara otomatis, bisa dinyatakan eksplisit dengan -F ~/.ssh/config

Menyalin public key ssh-copy-id

  • ssh-copy-id adalah utilitas kecil untuk cepat mengunggah public key ke server
  • Perintah yang digunakan
    • ssh-copy-id -i internal-web root@internal-web.int
  • Penjelasan opsi
    • -i internal-web: menentukan nama private key yang dipakai untuk autentikasi ke server
    • root@internal-web.int: menentukan server tujuan upload public key

Membuat dan memeriksa kunci dengan ssh-keygen

  • ssh-keygen adalah utilitas untuk membuat pasangan private key dan public key
  • Umumnya disarankan menggunakan opsi -b untuk menentukan ukuran kunci yang lebih besar
  • Ukuran kunci default pada lingkungan contoh adalah 3072
  • Algoritme default adalah RSA, tetapi algoritme lain dapat ditentukan dengan flag -t
    • Contoh: ssh-keygen -t ecdsa -b 521
  • Fingerprint dan ukuran byte kunci bisa diperiksa dengan perintah berikut
    • ssh-keygen -lf <file-name>

1 komentar

 
GN⁺ 2023-08-24
Komentar Hacker News
  • Ada satu direktif yang sangat sederhana tetapi terlewat di sini: atur di sshd_config seperti AuthorizedKeysCommand /usr/bin/php /etc/ssh/auth.php %u, lalu di skrip ambil https://github.com/{$user}.keys dari GitHub
    Tentu ini bukan kode berkualitas produksi, tetapi menunjukkan intinya
    Setelah memeriksa apakah pengguna merupakan anggota organisasi/grup GitHub, jika pengguna itu ada dan dipetakan dengan sesuatu seperti nss-ato, login ke server bisa diizinkan
    Saat onboarding/offboarding orang, akses ke mesin bisa diberikan atau dicabut cukup dengan menambahkan/menghapus mereka dari grup GitHub, sehingga kerepotannya berkurang

    • Amazon Linux juga melakukan hal serupa, tetapi mungkin karena berkualitas produksi, implementasinya jauh lebih rumit
      Di Amazon Linux 2 ke bawah, ia memanggil command line openssl untuk memeriksa format tiap kunci di file authorized_keys, tetapi karena di-hardcode ke RSA, meskipun versi OpenSSH mendukung ed25519, autentikasi dengan ed25519 ke host Amazon Linux 2 tidak bisa dilakukan
      Secara teori ini bagus karena memungkinkan fitur keren¹, tetapi dalam praktiknya, bagi orang yang tidak memakai fitur itu pun fungsi dasar menjadi rusak, sehingga membuat Amazon Linux terasa kurang dapat dipercaya
      Saat pertama kali mengalami masalah ini, saya sedang mencoba SSH ke mesin milik rekan DevOps yang cloud-first, dan karena saya tidak bisa mengaksesnya langsung, diagnosisnya sulit
      Ia sangat paham AWS tetapi kurang paham Linux, sehingga tidak tahu harus melihat ke mana; ia memilih Amazon Linux karena itu distro buatan pemilik platform cloud dan mengira akan “lebih kompatibel”, tetapi di sini “lebih kompatibel” sebenarnya berarti “lebih banyak kejutan bodoh”
      ¹ https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-...
    • Melihat hal seperti ini, rasanya sayang berada di sisi jaringan
      Karena cakupan kerja saya adalah “jaringan tidak berfungsi dengan benar”, fitur-fitur keren seperti ini jadi terlewat
    • Untuk penggunaan seperti ini, sebaiknya gunakan sertifikat SSH sebagai gantinya
  • Sepertinya banyak orang tidak tahu bahwa parser konfigurasi OpenSSH mengabaikan direktif duplikat, dan dari direktif yang sama hanya yang pertama yang berlaku
    Pada parser konfigurasi atau rule engine biasanya direktif yang muncul belakangan menimpa yang sebelumnya, jadi ini cukup berlawanan dengan intuisi
    Ini mungkin terlihat sepele, tetapi saat mengubah nilai default seperti /etc/ssh/sshd_config, manusia maupun perangkat lunak cenderung menambahkan perubahan di akhir file atau blok direktif, dan berharap perubahan itu diterapkan
    Perusahaan atau organisasi keamanan, berbagai produk bastion SSH, juga sering salah soal ini; rekomendasi CIS Benchmarks dan sebagian besar alat audit CIS pihak ketiga juga tidak mempertimbangkan prioritas atau menanganinya dengan keliru
    Untuk memastikan direktif konfigurasi OpenSSH didefinisikan sesuai harapan, jangan menelusuri file konfigurasi secara langsung; dump konfigurasi internal yang dihasilkan dengan sshd -T atau ssh -G

    • File sudoers juga bekerja dengan cara yang sama
      Untuk perangkat lunak autentikasi/otorisasi pengguna, saya menganggap cara ini memang diinginkan
      Sebab ini memudahkan membuat pengaturan yang tidak bisa ditimpa hanya dengan menambahkan file baru ke direktori whatever.conf.d
      Cukup definisikan pengaturan tersebut di file konfigurasi utama sebelum memuat whatever.conf.d/*, lalu beri perlindungan khusus pada file itu
      Bahkan jika bukan situasi seseorang mencoba melewati kontrol, ini menguntungkan untuk manajemen konfigurasi, karena pengaturan dasar tetap punya prioritas meskipun pegawai baru yang tidak tahu konteks penuh menambahkan file baru, atau suatu paket memasang default aneh untuk layanannya sendiri
      Alasan perilaku sebaliknya lebih sering terlihat dalam konteks lain adalah karena yang diinginkan bukan “pengaturan dasar”, melainkan default dalam arti ketat: nilai yang dipakai ketika pengguna/pengembang/admin tidak menetapkannya secara eksplisit
    • Sebagian direktif tampaknya bisa diduplikasi. Misalnya AllowUsers
      Namun kemarin NixOS tiba-tiba mengubah urutan penggabungan, sehingga AllowUsers di file saya turun ke bawah Match di file lain dan terkunci
  • Penjelasan dalam artikel bahwa pada -L untuk forwarding lokal, lokal berada di sisi kiri alamat, sedangkan pada -R untuk forwarding jarak jauh, port lokal berada di sisi kanan alamat, adalah kalimat paling penting dan ringkas
    Sejak awal saya bingung dengan -L dan -R, dan cukup merepotkan bahwa instance port mana yang lokal berubah tergantung L/R
    Saya paham bahwa -L dan -R mengubah arah yang dimaksud, yaitu di mana pihak pemulai dan pihak penanggap berada, tetapi rasanya tidak masalah juga jika port:address:port selalu berarti local:binding:remote, lalu -L/-R menentukan sisi mana yang menerima dan sisi mana yang mengirim

    • Cara paling mudah mengingatnya: -L mendengarkan pada port lokal yang nomornya muncul tepat setelahnya, sedangkan -R mendengarkan pada port jarak jauh yang nomornya muncul tepat setelahnya
      Sisa host:port hanyalah format umum yang memberi tahu ke mana harus terhubung
      Karena ini melakukan port forwarding melalui tunnel SSH, secara alami host tersebut dihubungi dari sisi yang berlawanan dengan port penerima di dalam tunnel
  • Salah satu fitur SSH yang kurang dikenal tetapi berguna adalah connection multiplexing
    Alih-alih membuat koneksi TCP baru dan menjalani prosedur autentikasi lagi, kita bisa membuatnya menggunakan kembali koneksi yang sudah ada
    Protokolnya sendiri memiliki konsep channel, dan setiap frame data diberi metadata untuk membedakan stream yang berbeda; fitur ini memanfaatkan hal itu
    Keuntungan besarnya adalah sesi berikutnya tidak perlu mengulang autentikasi penuh
    Ini terutama bagus jika di remote tidak ada tmux dan kita memakai beberapa panel lewat beberapa jendela terminal, dan akan makin terasa jika autentikasi melibatkan prosedur yang memakan beberapa detik seperti passphrase atau sentuhan HSM
    Ada juga pengaturan “connection persistence”, sehingga tidak perlu autentikasi ulang setiap kali berpindah di antara beberapa server
    Secara keseluruhan, saya melihatnya sebagai fitur yang menyenangkan untuk ada, tetapi bukan sesuatu yang sampai mengubah hidup
    Di sebagian server fitur ini dimatikan, dan ketidakhadirannya lebih terasa saat dimatikan daripada saat dinyalakan
    Lihat selengkapnya: https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing

    • Jika latensi antara klien dan server besar, perbedaannya sangat besar
      Tidak seperti TLS yang dioptimalkan untuk mengurangi jumlah round-trip, SSH adalah protokol yang cukup cerewet, dan opsi multiplexing ini hampir satu-satunya pengecualian
    • Saat melewati host bastion ProxyJump, ini bisa membuat Ansible jauh lebih nyaman dipakai
  • Jika ada banyak host di ~/.ssh/config, direktif Include yang mendukung wildcard bisa mencegah file menjadi terlalu berantakan
    Misalnya, di ~/.ssh/config kita bisa menaruh Include config.d/*.conf, lalu memisahkan pengaturan host, hostname, dan user masing-masing ke ~/.ssh/config.d/work.conf atau client1.conf

    • Direktif Host juga mendukung wildcard
      Misalnya, kita bisa menambahkan host *_work dan memasukkan pengaturan umum untuk semua host kerja seperti host1_work
    • Sebagai kiat tambahan, Include bisa diletakkan di dalam direktif Host/Match
      Misalnya, jika menaruh Host proj1.*.corp dan Include ~/.ssh/proj1.conf di ~/.ssh/config, pencocokan per proyek bisa ditempatkan dekat bagian atas, dan saat meninjau konfigurasi kita tidak perlu membongkar begitu banyak file terpisah
  • Saat melakukan forwarding, saya hampir tidak pernah memakai -f
    Ini bisa menjadi senjata makan tuan karena membuat sulit mengetahui forwarding mana yang masih terbuka dan sedang berjalan
    -t adalah trik yang keren, dan ini fitur yang sebelumnya tidak saya ketahui
    Hal penting yang mudah terlewat dari daftar perintah escape ~ adalah bahwa escape juga bisa dinesting di dalam sesi yang nested
    Ini berguna ketika, karena alasan apa pun, kita tidak memakai -J
    Daftarnya cocok dengan hal-hal yang berguna, dan ada beberapa hal tambahan yang juga saya pelajari

    • -t itu luar biasa. Saya memakainya seperti ssh -t my-dev-vps 'tmux new-session -A -s main', sehingga setiap kali dijalankan saya langsung kembali ke posisi terakhir di sesi tmux
    • Jika beberapa shell dibiarkan terbuka di server target, masalah yang sama tetap ada
      Akan bagus jika SSH bisa mengekspor status forwarding dengan cara yang masuk akal, bukan harus mengorek sendiri daftar proses
  • Saat ini ada pull request untuk menambahkan dukungan AF_UNIX, dan jika ini masuk, berbagai forwarding menarik akan menjadi mungkin
    Sebab, akan menjadi mudah mem-proxy koneksi SSH melalui proses lokal sembarang, dan proses itu bisa menangani sendiri bagaimana data diteruskan sampai ke ujung remote
    https://github.com/openssh/openssh-portable/pull/431

    • Yang menarik bagi saya adalah -D yang memakai AF_UNIX, tetapi bagus juga jika semuanya bisa berjalan di atas AF_UNIX
      Sepertinya sejak sekitar setahun lalu curl bisa memakai SOCKS AF_UNIX lewat sintaks ALL_PROXY socks5://localhost/path atau socks5h
      Tampaknya ini ditambahkan karena Tor memakai proxy SOCKS AF_UNIX
      Akan bagus jika akses jaringan bisa diatur dengan permission Unix standar, dan secara pribadi akan lebih bagus lagi jika TCP/IP bisa disingkirkan sepenuhnya dari kernel
  • Saya terkejut saat pertama kali melihat konsol SSH
    Seorang kolega menunjukkan ~#, dan rasanya seperti menemukan menu cheat rahasia yang mungkin muncul di game SEGA Genesis

  • Mengapa tilde? Karena rlogin dan rsh memakainya
    Mengapa rlogin dan rsh memakai tilde? Karena cu memakainya
    Mengapa cu? Jika ada modem atau jalur serial, kita berkomunikasi dengan cu, dan perlu mengirim kode Hayes; tetapi jika memakai escape sequence kode Hayes, kita akan masuk ke modem, jadi diperlukan sinyal terpisah untuk keluar ke cu
    Mengapa bukan ^[? Karena itu milik telnet
    Jadi jika kita terhubung ke host lewat telnet lalu menyambung ke modem dengan cu, kita membutuhkan sintaks escape terpisah untuk kembali ke cu tanpa keluar ke telnet
    Pada akhirnya ini adalah struktur escape syntax yang menumpuk tanpa henti
    Dan sebenarnya bukan tilde, melainkan tilde

    • Saya kira urutannya CR, tilde, lalu ., apakah selama ini saya memakainya dengan salah?
  • Bagian ssh-copy-id awalnya menjelaskan bahwa perintah itu mengunggah public key, lalu tiba-tiba berubah menjadi mengunggah private key, jadi tampaknya itu typo
    Selain itu, perintah ini bukan sekadar mengunggah key, melainkan menambahkannya ke ~/.ssh/authorized_keys, sehingga jauh lebih berguna
    Terakhir, pada bagian ssh-keygen, dari materi yang saya baca belakangan ini ed25519 lebih disukai daripada ecdsa