HTTPS経由のSSH接続
(trofi.github.io)- 制限の厳しいネットワークでも
SSHポートが塞がれていても、HTTPS 443ポート とCONNECTメソッドを使ってリモート接続経路を作れる - サーバー側では
apache2のmod_proxy_connectでCONNECTを有効にしつつ、ssh-server:22 宛てだけを許可してプロキシ範囲を狭める - クライアント側では OpenSSH の ProxyCommand と
socatを組み合わせ、HTTPS ではスクリプトがCONNECTヘッダーを直接送る - 一部のファイアウォールや
httpdはアイドル接続を閉じることがあるため、ServerAliveInterval 30で セッション維持 を補助する - この方法は
SSHをTLSの中にカプセル化して遮断を回避しやすい一方、二重暗号化 とクライアント設定の負担は残る
制限されたネットワークでSSH接続経路を作る
- 病院の Wi-Fi 環境では大半の接続方式が遮断され、主に
HTTPの TCP 80 とHTTPSの TCP 443 だけが許可されていた DNSの UDP 53 とDoTの TCP 853 は、よく知られた DNS プロバイダーに対しては動作しているようだったSSHは TCP 22 とほとんどのカスタムポートが完全に遮断されていた- リモートサーバーを再設定できる
GSMの代替接続があり、さまざまな回避方法を試せた
1つのポート共有とプロトコルのカプセル化
- 1つのポートで
SSHとHTTPSを同時に受け付け、透過的に振り分ける方法がある- sslh project はヒューリスティックでプロトコルを推定し、実際のバックエンドである
SSH、HTTPS、または対応プロトコルへリダイレクトする - 利点は
sshクライアントに特別な設定が不要で、非標準ポートを指定するだけでよいこと - 欠点は追加サービスの設定が必要で、
HTTPSもsslhを経由しなければならず、バックエンドでは接続の 元のアドレス が隠れてログ取得が不便になることがある点
- sslh project はヒューリスティックでプロトコルを推定し、実際のバックエンドである
- 別の選択肢は、あるプロトコルを別のプロトコルの中に完全に カプセル化 する方法
- OpenSSH の
ProxyCommandは、sshプロトコルが使う転送手段をユーザーが指定できるようにする - ヒューリスティックなしで
SSHを別のストリームに包むため、DPI ソフトウェアによる遮断がより難しくなる可能性がある HTTPS自体はリダイレクトされたり影響を受けたりしない- その代わり 二重暗号化 により性能が低下する可能性があり、クライアント設定も必要になる
- OpenSSH の
SSH over HTTP の構成
- まず
SSHをHTTPで通す方法を試した - サーバー側の
apache2設定ではmod_proxy_connectをロードし、AllowCONNECT 22で 22番ポートへの CONNECT を許可する <Proxy *>はデフォルトですべて拒否し、<Proxy ssh-server>だけを許可して対象をssh-server:22に限定する- クライアント側の
.ssh/configでは、ProxyCommandでsocatのPROXY:http-server:%h:%p,proxyport=80を使う - この設定で
$ ssh ssh-via-httpを実行すると、80番ポート 経由でSSHに接続できる ServerAliveInterval 30は、中継経路でアイドル状態のHTTP接続が黙って閉じられる事態を避けるため、定期的にプローブを送る- デフォルトの
httpdは、入出力のない状態が 60秒 続くとトンネルを閉じるTimeOut 60を使う
SSH over HTTPS の構成
socatはCONNECTメソッドによるHTTPSプロキシをサポートせず、HTTPのみをサポートしているようだった- そこで代わりに
socatの TLS カプセル化 機能を使い、CONNECTベースのリクエストはスクリプト側で直接実装する ~/.ssh/https-tunnel.bashは次の流れで動作する- まず
CONNECT ssh-server:22 HTTP/1.1ヘッダーとHost: ssh-serverを出力する - その後、標準入力をそのまま連結する
- ストリーム全体を
socat - "SSL:$3:$4"に渡して TLS 接続 を作る
- まず
.ssh/configではHost ssh-via-httpsに対してProxyCommand ~/.ssh/https-tunnel.bashを指定する$ ssh ssh-via-httpsを実行すると、期待どおりHTTPSトンネル経由でssh-serverに接続できる
運用時の注意点
HTTPSが広く許可されている環境では、非常に制限の厳しい中間機器を通してデータを届けられるCONNECTメソッドは古い名残のように見えるが、任意の TCP ペイロードストリーム をTLSホストストリームの中に包むのに有用ServerAliveIntervalは、下位の転送層がアイドル接続に友好的でない場合でも OpenSSH 接続の維持に役立つnginxの構成バリエーションは CONNECT passthrough on nginx にある
1件のコメント
Hacker News のコメント
記事の「HTTPS はどこにでもあるため、非常に制限の厳しい中間機器でもデータを通過させられる」という部分こそが、ほぼすべての独自 VPN プロトコル、いわゆる「SSL VPN」が HTTPS でトンネルを張るモードを実装している理由です。
デフォルト動作でなくても、少なくとも代替経路として用意し、世界中のインターネット上のほぼどんな接続でも動作するモードを確保するのが目的です。
複数の TLS ベース VPN プロトコルを実装する https://gitlab.com/openconnect/openconnect の主要開発者の一人であり、より多くの TLS ベース VPN サーバー種別を検出・識別する https://github.com/dlenski/what-vpn も作りました。
以前、オランダのインターネットプロバイダー XS4ALL がまさにこういう機能を提供していました。
ポート 80 で SSH 接続を開放していて、旅行中にホテルの WiFi がポート 80 以外をすべて塞いでいたとき、何度も助かりました。
ただ、KPN からすれば XS4ALL のハッカー文化はそもそも居心地のよいものではなかったのでしょう。
1960年代の海賊ラジオ文化の再現のように感じました。
https://en.wikipedia.org/wiki/Pirate_radio_in_Europe
https://www.shodan.io/search/facet?query=ssh&facet=port
https://www.shodan.io/search/facet.png?query=ssh&facet=port
一方でポート 80 はずっと珍しいです。
昔はニュースグループプロバイダーとしてだけ使っていた記憶があります。
第三の選択肢もよくあります。別ホストのポート 80 や 443 に SSH を立てておき、そこから目的地へ ProxyJump する方法です。
あるいは、そのホストへ SOCKS を開いて、全体的にフィルタリングの緩いインターネット接続を得ることもできます。
私は SOCKS を使い、SSH 接続のポートフォワーディングで TLS ベースの DNS も流しています。
数年前に SOCKS プロキシを初めて設定して WiFi をかなり使ったときは、ポートを確認する以上のことをしている場所は見かけませんでしたが、そういう機器は存在しますし、今ではより一般的かもしれません。
そこで単に自分のサーバーへ SSH 接続して、いつもどおり使っていました。
後に Windows の
.isoファイルアーカイブを作り、ノート PC にダウンロードしてscpでサーバーにアップロードしたところ、80/443 以外のポートでアップロード・ダウンロード合計数十 GB を使う程度でもトラフィック検査を誘発するには十分だったのか、昼ごろに IT 部門がポート 22 を塞ぎました。ところが他のポートは塞がれていなかったため、ポートフォワーディングで SSH を 443 に移して使い続けました。
その後、学校の IT 部門が 443 で SSH を使っていることに気づき、80/443 上の SSH をブロックする基本的なトラフィック分析を入れましたが、それでも他のすべてのポートは開いたままでした。
最終的に私のサーバーを IP 単位でブロックしましたが、他の IP はすべて開いたままでした。
VPS で ProxyJump を使えば回避できますが、早期大学高校課程だったので2年以降は学校にほとんど行かず、手間をかける価値はあまりありませんでした。
次に行くときは可能だと証明するために試すつもりで、もし全ポートの SSH を塞がれたら、VPS に HTTPS 上の SSH を載せれば済みます。
卒業後はゲスト WiFi でどこまで可能か、また見てみるつもりです。
少し露骨な宣伝ですが、Adaptive [1] ではデータセキュリティインフラを作っています。
製品の一つでは、SSH とその他いくつかのプロトコルを HTTP/3 上で転送し、ユーザーが単一のアウトバウンドポートでデータベース、サーバー、その他のリソースに接続できるようにしています。
Ngrok 系に似ていますがセルフホスト可能で、パスワードなしでアクセスしたり、一時的な認証情報や maker-checker 保護を付けたりできます。
[1] https://adaptive.live/
実際には、
opensshを443番ポートで待ち受けさせるだけでも、ほとんどのファイアウォールを回避できました。良いですね。不思議なことに、
CONNECTメソッドをフォワードプロキシではなくリバースプロキシのように考えたことはありませんでした。ただ私の場合は
CONNECTだけでは足りず、社内プロキシを抜けるために WebSocket 上で SSH を使いました。そのプロキシはカスタム CA で HTTPS 接続を検査していました。
socatを修正して Apache 経由で自分の SSH サーバーを WebSocket として提供し、クライアント側では OpenSSH のProxyCommandと一緒に使いました。そのパッチを公開しようと思っているだけの状態ですが、
websocatのような他の選択肢もあります。ほぼ20年前、会社のファイアウォールに穴を開けようとして、まさにこれを行うツール corkscrew[0] を使っていた
スタンドアロン実装と記事はすっきりしている
0: https://github.com/bryanpkc/corkscrew
corkscrewは特定の条件でしか動作しない: HTTPプロキシの背後にいて、そのHTTPプロキシがCONNECTメソッドをサポートしている必要がある約20年前に短期の契約仕事をしたときは、1つ目の条件は満たしていたが、2つ目の条件は満たしていなかった
幸い、この場合でも使えるツールがあり、もちろんサーバー側の設定が必要になる
https://github.com/larsbrinkhoff/httptunnel
全体として HTTP/2経由のトンネリング は良い選択であることが分かった
HTTP/2上に構築されたリモートプロシージャコールプロトコルとして gRPC[1] がある
HTTP/2は、1本のTCP接続を使って複数のデータ構造を同時に送受信する多重化に強いからだ
ただしQUIC自体が多重化を提供するため、HTTP/3を使う理由はないかもしれない
今後は、中間機器メーカーが差別的な扱いをやめられないため、ほとんどの通信は暗号化されたHTTP/2とQUIC上に移っていきそうだ
能動的探査[2]を緩和するために、ランダムな、場合によってはAI生成のHTTP/2・HTTP/3コンテンツを提供する必要があるかもしれない
[1] <https://grpc.io>
[2] <https://blog.torproject.org/learning-more-about-gfws-active-...>
HTTP自体がすでにリクエスト/レスポンスプロトコルであり、基本的にリモートプロシージャコールに使える
HTTP 1、2、3のどれでも大きな違いはなさそうに見える
そのプロトコルの進化自体もやや疑わしく、リモートプロシージャコール環境では不要なものを活用するよう設計されている面がある
本質的にはローカルサービスではなく 公開インターネット のために設計されたものに近い
HTTP/3はQUIC上で動作する
私は逆に SSH上のHTTP のほうが好みだ
半分冗談だが、ブラウザにSSH相当のアイデンティティ管理が組み込まれるといいと思う
公開鍵HTTP認証の提案である hobo を初めて読んだときは興奮したが、サーバー実装もブラウザクライアント実装もないことを知った
JavaScript実装はあるが、望んでいた形ではなかった
ssh -D “*:8080” hostこのコマンドは8080番ポートに SOCKSプロキシ を立ち上げる
Firefoxでいつも使っており、元祖VPNのように動作する
怪しい用途にも便利だが、AWSのプライベートネットワークにある rmq ダッシュボードへアクセスするときにも使っている
https://techcommunity.microsoft.com/t5/iis-support-blog/clie...
要件に合うか分かるほど詳しくはないが、大学時代にサーバー認証で使ったことはある
ssh://google.comが使えたらよかったのにhttps://news.ycombinator.com/item?id=38664729
sslhはなぜ愛されないのか?HTTP、TLS/SSL(SNIとALPNを含む)、SSH、OpenVPN、tinc、XMPP、SOCKS5を検出し、正規表現で検査できる他のプロトコルも認識できる
典型的な用途は、443番ポートで複数のサービスを同時に提供することだ
たとえば、会社のファイアウォール内からSSHに接続しつつ、同じポートでHTTPSの提供を継続できる
https://www.rutschle.net/tech/sslh/README.html
sslhと 完全カプセル化 のどちらを選ぶかについての内容だった完全カプセル化を選んだ理由は、設定するサービスが1つ減ること、HTTPサーバーが接続を処理するためログのリモートアドレスが正確になること、そしておそらくハッカー精神として既存の解決策より新しい解決策を好むからだと思われる