3 ポイント 投稿者 GN⁺ 2023-12-25 | 1件のコメント | WhatsAppで共有
  • 制限の厳しいネットワークでも SSH ポートが塞がれていても、HTTPS 443ポートCONNECT メソッドを使ってリモート接続経路を作れる
  • サーバー側では apache2mod_proxy_connectCONNECT を有効にしつつ、ssh-server:22 宛てだけを許可してプロキシ範囲を狭める
  • クライアント側では OpenSSH の ProxyCommandsocat を組み合わせ、HTTPS ではスクリプトが CONNECT ヘッダーを直接送る
  • 一部のファイアウォールや httpd はアイドル接続を閉じることがあるため、ServerAliveInterval 30セッション維持 を補助する
  • この方法は SSHTLS の中にカプセル化して遮断を回避しやすい一方、二重暗号化 とクライアント設定の負担は残る

制限されたネットワークでSSH接続経路を作る

  • 病院の Wi-Fi 環境では大半の接続方式が遮断され、主に HTTPTCP 80HTTPSTCP 443 だけが許可されていた
  • DNSUDP 53DoTTCP 853 は、よく知られた DNS プロバイダーに対しては動作しているようだった
  • SSHTCP 22 とほとんどのカスタムポートが完全に遮断されていた
  • リモートサーバーを再設定できる GSM の代替接続があり、さまざまな回避方法を試せた

1つのポート共有とプロトコルのカプセル化

  • 1つのポートで SSHHTTPS を同時に受け付け、透過的に振り分ける方法がある
    • sslh project はヒューリスティックでプロトコルを推定し、実際のバックエンドである SSHHTTPS、または対応プロトコルへリダイレクトする
    • 利点は ssh クライアントに特別な設定が不要で、非標準ポートを指定するだけでよいこと
    • 欠点は追加サービスの設定が必要で、HTTPSsslh を経由しなければならず、バックエンドでは接続の 元のアドレス が隠れてログ取得が不便になることがある点
  • 別の選択肢は、あるプロトコルを別のプロトコルの中に完全に カプセル化 する方法
    • OpenSSH の ProxyCommand は、ssh プロトコルが使う転送手段をユーザーが指定できるようにする
    • ヒューリスティックなしで SSH を別のストリームに包むため、DPI ソフトウェアによる遮断がより難しくなる可能性がある
    • HTTPS 自体はリダイレクトされたり影響を受けたりしない
    • その代わり 二重暗号化 により性能が低下する可能性があり、クライアント設定も必要になる

SSH over HTTP の構成

  • まず SSHHTTP で通す方法を試した
  • サーバー側の apache2 設定では mod_proxy_connect をロードし、AllowCONNECT 2222番ポートへの CONNECT を許可する
  • <Proxy *> はデフォルトですべて拒否し、<Proxy ssh-server> だけを許可して対象を ssh-server:22 に限定する
  • クライアント側の .ssh/config では、ProxyCommandsocatPROXY:http-server:%h:%p,proxyport=80 を使う
  • この設定で $ ssh ssh-via-http を実行すると、80番ポート 経由で SSH に接続できる
  • ServerAliveInterval 30 は、中継経路でアイドル状態の HTTP 接続が黙って閉じられる事態を避けるため、定期的にプローブを送る
  • デフォルトの httpd は、入出力のない状態が 60秒 続くとトンネルを閉じる TimeOut 60 を使う

SSH over HTTPS の構成

  • socatCONNECT メソッドによる HTTPS プロキシをサポートせず、HTTP のみをサポートしているようだった
  • そこで代わりに socatTLS カプセル化 機能を使い、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件のコメント

 
GN⁺ 2023-12-25
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 以外をすべて塞いでいたとき、何度も助かりました。

    • XS4ALL は素晴らしかったですし、KPN がそのブランドを廃止することにしたのは本当に残念です。
      ただ、KPN からすれば XS4ALL のハッカー文化はそもそも居心地のよいものではなかったのでしょう。
    • XS4ALL のユーザーでしたが、本当に素晴らしく、初期インターネットの精神が息づいていました。
      1960年代の海賊ラジオ文化の再現のように感じました。
      https://en.wikipedia.org/wiki/Pirate_radio_in_Europe
    • SSH の非標準ポートの中では、443番ポートは上位に入ります。
      https://www.shodan.io/search/facet?query=ssh&facet=port
      https://www.shodan.io/search/facet.png?query=ssh&facet=port
      一方でポート 80 はずっと珍しいです。
    • XS4ALL が完全なインターネットプロバイダーだったとは知りませんでした。
      昔はニュースグループプロバイダーとしてだけ使っていた記憶があります。
    • XS4ALL は、ある程度 Freedom という形で受け継がれています: https://freedom.nl/en
  • 第三の選択肢もよくあります。別ホストのポート 80 や 443 に SSH を立てておき、そこから目的地へ ProxyJump する方法です。
    あるいは、そのホストへ SOCKS を開いて、全体的にフィルタリングの緩いインターネット接続を得ることもできます。
    私は SOCKS を使い、SSH 接続のポートフォワーディングで TLS ベースの DNS も流しています。
    数年前に SOCKS プロキシを初めて設定して WiFi をかなり使ったときは、ポートを確認する以上のことをしている場所は見かけませんでしたが、そういう機器は存在しますし、今ではより一般的かもしれません。

    • 高校1年のときにセルフホスティングを始めたばかりでしたが、学校は Web サイトはブロックしていたものの、ポートブロックはまったくしていませんでした。
      そこで単に自分のサーバーへ 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/

  • 実際には、openssh443番ポートで待ち受けさせるだけでも、ほとんどのファイアウォールを回避できました。

  • 良いですね。不思議なことに、CONNECT メソッドをフォワードプロキシではなくリバースプロキシのように考えたことはありませんでした。
    ただ私の場合は CONNECT だけでは足りず、社内プロキシを抜けるために WebSocket 上で SSH を使いました。
    そのプロキシはカスタム CA で HTTPS 接続を検査していました。
    socat を修正して Apache 経由で自分の SSH サーバーを WebSocket として提供し、クライアント側では OpenSSH の ProxyCommand と一緒に使いました。
    そのパッチを公開しようと思っているだけの状態ですが、websocat のような他の選択肢もあります。

    • だから多くの企業プロキシやファイアウォールは、WebSocket をデフォルトでブロックしているようです。
    • 意図せず huproxy を再発明したように聞こえます。
  • ほぼ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自体がすでにリクエスト/レスポンスプロトコルであり、基本的にリモートプロシージャコールに使える
      HTTP 1、2、3のどれでも大きな違いはなさそうに見える
      そのプロトコルの進化自体もやや疑わしく、リモートプロシージャコール環境では不要なものを活用するよう設計されている面がある
      本質的にはローカルサービスではなく 公開インターネット のために設計されたものに近い
    • SSHの場合、接続は1本だけで、実際にはSSHが独自に 多重化 を実装しているので、HTTP/2の利点はよく見えない
    • HTTP/2は依然としてTCPなので、TCPのヘッドオブラインブロッキング の影響を受ける
      HTTP/3はQUIC上で動作する
  • 私は逆に SSH上のHTTP のほうが好みだ
    半分冗談だが、ブラウザにSSH相当のアイデンティティ管理が組み込まれるといいと思う
    公開鍵HTTP認証の提案である hobo を初めて読んだときは興奮したが、サーバー実装もブラウザクライアント実装もないことを知った
    JavaScript実装はあるが、望んでいた形ではなかった

    • ssh -D “*:8080” host
      このコマンドは8080番ポートに SOCKSプロキシ を立ち上げる
      Firefoxでいつも使っており、元祖VPNのように動作する
      怪しい用途にも便利だが、AWSのプライベートネットワークにある rmq ダッシュボードへアクセスするときにも使っている
    • HTTPSクライアント証明書 はどうだろう?
      https://techcommunity.microsoft.com/t5/iis-support-blog/clie...
      要件に合うか分かるほど詳しくはないが、大学時代にサーバー認証で使ったことはある
    • 言っているのは パスキー のことでは?
    • ブラウザで ssh://google.com が使えたらよかったのに
    • 先週見逃していたなら、似た方向の記事があった: SSH3、HTTP/3とQUICを使うSSHv2
      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サーバーが接続を処理するためログのリモートアドレスが正確になること、そしておそらくハッカー精神として既存の解決策より新しい解決策を好むからだと思われる