Saya telah mencari solusi untuk masalah ini hidup dan mati selama 16 bulan terakhir. Tetapi setiap kali saya melihat, tampaknya tidak mungkin untuk melakukan ini dengan protokol SSH sebagaimana ditentukan dalam RFC yang relevan dan diimplementasikan oleh implementasi besar.
Namun jika Anda bersedia untuk menggunakan klien SSH yang sedikit dimodifikasi dan Anda bersedia untuk menggunakan protokol dengan cara yang tidak persis dimaksudkan ketika mereka dirancang, maka itu mungkin untuk dicapai. Lebih lanjut tentang ini di bawah ini.
Kenapa itu tidak mungkin
Klien tidak mengirim nama host sebagai bagian dari protokol SSH.
Mungkin mengirim nama host sebagai bagian dari pencarian DNS, tetapi itu mungkin di-cache, dan jalur dari klien melalui resolvers ke server otoritatif mungkin tidak melewati proxy, dan bahkan jika itu terjadi, tidak ada cara yang kuat untuk mengaitkan pencarian DNS tertentu dengan klien SSH tertentu.
Tidak ada yang mewah yang dapat Anda lakukan dengan protokol SSH itu sendiri. Anda harus memilih server tanpa melihat spanduk versi SSH dari klien. Anda harus mengirim spanduk ke klien, sebelum itu akan mengirim apa pun ke proxy. Spanduk dari server bisa berbeda, dan Anda tidak memiliki kesempatan untuk menebak, mana yang benar untuk digunakan.
Meskipun spanduk ini dikirim tanpa enkripsi, Anda tidak dapat memodifikasinya. Setiap bit dari spanduk itu akan diverifikasi selama pengaturan koneksi, jadi Anda akan menyebabkan kegagalan koneksi sedikit di telepon.
Kesimpulannya bagi saya cukup jelas, kita harus mengubah sesuatu di sisi klien untuk membuat konektivitas ini berfungsi.
Sebagian besar solusi adalah merangkum lalu lintas SSH di dalam protokol yang berbeda. Orang juga bisa membayangkan penambahan pada protokol SSH itu sendiri, di mana banner versi yang dikirim oleh klien menyertakan nama host. Ini dapat tetap kompatibel dengan pengungkit yang ada, karena bagian dari spanduk saat ini ditentukan sebagai bidang identifikasi formulir gratis, dan meskipun klien biasanya menunggu spanduk versi dari server sebelum mengirimkan milik mereka, protokol tersebut mengizinkan klien untuk mengirim spanduk mereka. pertama. Beberapa versi terbaru dari ssh client (misalnya yang ada di Ubuntu 14.04) mengirim banner tanpa menunggu banner server.
Saya tidak tahu ada klien, yang telah mengambil langkah-langkah untuk memasukkan nama host dari server di spanduk ini. Saya telah mengirim patch ke milis OpenSSH untuk menambahkan fitur seperti itu. Tapi itu ditolak berdasarkan keinginan untuk tidak mengungkapkan nama host kepada siapa pun yang mengintip lalu lintas SSH. Karena nama host rahasia pada dasarnya tidak sesuai dengan operasi proksi berbasis nama, jangan berharap untuk melihat ekstensi SNI resmi untuk protokol SSH dalam waktu dekat.
Solusi nyata
Solusi yang paling berhasil bagi saya adalah menggunakan IPv6.
Dengan IPv6 saya dapat memiliki alamat IP terpisah yang ditetapkan untuk setiap server, sehingga gateway dapat menggunakan alamat IP tujuan untuk mengetahui server mana yang akan dikirimi paket. Klien SSH kadang-kadang mungkin berjalan di jaringan di mana satu-satunya cara untuk mendapatkan alamat IPv6 adalah dengan menggunakan Teredo. Teredo diketahui tidak bisa diandalkan, tetapi hanya ketika ujung IPv6 asli dari koneksi menggunakan relay Teredo publik. Seseorang bisa dengan mudah meletakkan relay Teredo di gateway, tempat Anda menjalankan proxy. Miredo dapat diinstal dan dikonfigurasi sebagai relay dalam waktu kurang dari lima menit.
Sebuah solusi
Anda dapat menggunakan host host / bastion. Pendekatan ini dimaksudkan untuk kasus-kasus di mana Anda tidak ingin mengekspos port SSH dari masing-masing server langsung ke internet publik. Itu memang memiliki manfaat tambahan untuk mengurangi jumlah alamat IP eksternal yang Anda butuhkan untuk SSH, itulah sebabnya mengapa ini dapat digunakan dalam skenario ini. Fakta bahwa itu adalah solusi yang dimaksudkan untuk menambahkan lapisan perlindungan lain untuk alasan keamanan tidak mencegah Anda menggunakannya ketika Anda tidak membutuhkan keamanan tambahan.
ssh -o ProxyCommand='ssh -W %h:%p user1@bastion' user2@target
Kotor untuk diretas untuk membuatnya berfungsi jika solusi nyata (IPv6) berada di luar jangkauan Anda
Retas yang akan saya uraikan seharusnya hanya digunakan sebagai upaya terakhir. Bahkan sebelum Anda berpikir tentang menggunakan peretasan ini, saya sangat menyarankan untuk mendapatkan alamat IPv6 untuk masing-masing server yang ingin Anda jangkau secara eksternal melalui SSH. Gunakan IPv6 sebagai metode utama Anda untuk mengakses server SSH Anda dan hanya gunakan peretasan ini saat Anda perlu menjalankan klien SSH dari jaringan khusus IPv4 di mana Anda tidak memiliki pengaruh apa pun untuk menerapkan penyebaran IPv6.
Idenya adalah bahwa lalu lintas antara klien dan server harus benar-benar berlaku untuk lalu lintas SSH. Tetapi proxy hanya perlu cukup memahami tentang aliran paket untuk mengidentifikasi nama host. Karena SSH tidak menentukan cara untuk mengirim nama host, Anda dapat mempertimbangkan protokol lain yang memang menyediakan kemungkinan seperti itu.
HTTP dan HTTPS keduanya memungkinkan klien untuk mengirim nama host sebelum server mengirim data apa pun. Pertanyaannya sekarang adalah, apakah mungkin untuk membangun aliran byte yang secara simultan valid sebagai lalu lintas SSH dan sebagai HTTP dan HTTPS. HTTPs bukan non-starter, tetapi HTTP mungkin (untuk definisi HTTP yang cukup liberal).
SSH-2.0-OpenSSH_6.6.1 / HTTP/1.1
$:
Host: example.com
Apakah ini terlihat seperti SSH atau HTTP untuk Anda? Ini adalah SSH dan benar-benar sesuai RFC (kecuali beberapa karakter biner agak rusak oleh rendering SF).
String versi SSH menyertakan bidang komentar, yang di dalamnya memiliki nilai / HTTP/1.1
. Setelah baris baru SSH memiliki beberapa data paket biner. Paket pertama adalah MSG_SSH_IGNORE
pesan yang dikirim oleh klien dan diabaikan oleh server. Payload yang harus diabaikan adalah:
:
Host: example.com
Jika proxy HTTP cukup liberal dalam apa yang diterimanya, maka urutan byte yang sama akan ditafsirkan sebagai metode HTTP yang disebut SSH-2.0-OpenSSH_6.6.1
dan data biner pada awal pesan abaikan akan ditafsirkan sebagai nama header HTTP.
Proxy tidak akan mengerti metode HTTP atau header pertama. Tapi itu bisa memahami Host
header, yang dibutuhkan untuk menemukan backend.
Agar ini berfungsi, proksi harus dirancang dengan prinsip bahwa hanya perlu memahami cukup HTTP untuk menemukan backend, dan setelah backend ditemukan, proksi hanya akan melewati stream byte mentah dan meninggalkan penghentian nyata. koneksi HTTP yang harus dilakukan oleh backend.
Mungkin terdengar seperti peregangan untuk membuat begitu banyak asumsi tentang proksi HTTP. Tetapi jika Anda ingin menginstal perangkat lunak baru yang dikembangkan dengan maksud untuk mendukung SSH, maka persyaratan untuk proxy HTTP tidak terdengar terlalu buruk.
Dalam kasus saya sendiri, saya menemukan metode ini berfungsi pada proksi yang sudah diinstal tanpa mengubah kode, konfigurasi, atau lainnya. Dan ini untuk proxy yang ditulis hanya dengan HTTP dan tanpa SSH.
Bukti konsep klien dan proksi . (Penafian bahwa proxy adalah layanan yang dioperasikan oleh saya. Jangan ragu untuk mengganti tautan begitu proxy lain dikonfirmasi untuk mendukung penggunaan ini.)
Peringatan hack ini
- Jangan gunakan itu. Lebih baik menggunakan solusi nyata, yaitu IPv6.
- Jika proxy mencoba untuk memahami lalu lintas HTTP, itu pasti akan rusak.
- Mengandalkan klien SSH yang dimodifikasi tidak baik.