9 ポイント 投稿者 GN⁺ 2026-01-23 | 1件のコメント | WhatsAppで共有
  • SSHセッションで単一のキー入力時に数百個のパケットが送信される現象が見つかり、その原因を追跡した事例
  • tcpdump の分析結果、ほとんどのパケットは36バイトの繰り返しメッセージで構成されており、およそ20ms間隔で発生
  • 原因は2023年にSSHへ追加された**「キー入力タイミング難読化(keystroke timing obfuscation)」機能で、ユーザーの入力タイミングを隠すため多数の「chaff」パケット(SSH2_MSG_PING)**を送信していたこと
  • この機能を無効化するか、サーバーが [email protected] 拡張を広告しないよう修正すると、CPU使用率と帯域幅が半分以下に減少
  • SSHのセキュリティ機能が、**リアルタイム性能が重要なアプリケーション(例: ゲーム)**では大きな負荷として作用しうることを示す事例

問題の発見

  • SSH経由で動作する高性能ゲームのTUIをテストしていたところ、単一のキー入力でも270個のパケットが発生する現象を確認
    • tcpdump の結果、66%が36バイトのメッセージ、33%がTCP ACK、残りは少量のその他データ
    • 平均90パケット/秒、約11ms間隔でデータを送信
  • テスト中、サーバーが “your screen is too small” メッセージだけを送るよう誤設定されていたが、このときCPUと帯域幅の使用量が半分に減少
    • ゲームデータが送信されないならCPU使用率は0%近くであるべきだが、それでも50%程度を維持
    • これによりSSH自体の通信オーバーヘッドの可能性が浮上

調査プロセス

  • tcpdump を使って正常動作時とエラー状態のSSHトラフィックを比較
    • エラー状態でも36バイトのパケットが20ms間隔で継続発生
    • macOS標準のSSHクライアントでも同じパターンを確認
  • Claude Codeを使ってpcapファイルを分析した結果
    • 全413,703個のパケットのうち66%が36バイト、34%が0バイトACK
    • SSHクライアントが主導してパケットを生成していた

根本原因

  • SSHデバッグログ(ssh -vvv)で次のメッセージを確認
    obfuscate_keystroke_timing: starting: interval ~20ms
    obfuscate_keystroke_timing: stopping: chaff time expired (101 chaff packets sent)
    
    • 20ms間隔数十〜100個超のchaffパケットが、実際に観測されたパターンと一致
  • 2023年にSSHへ追加されたキー入力タイミング難読化機能が原因
    • ユーザーのタイピング速度パターンが露出するのを防ぐため、ランダムな「chaff」パケットを送信
    • セキュリティには有用だが、レイテンシが重要な環境では過剰な負荷を発生させる

解決方法

  • クライアント側では ObscureKeystrokeTiming=no オプションで機能を無効化可能
    • 適用後、CPU使用率と帯域幅が大幅に減少し、データ送信も正常に維持
  • サーバー側の対応として、GoのSSHライブラリで [email protected] 拡張の広告を削除
    • 関連コミットを取り消してテストした結果
      • CPU使用率 29.9% → 11.6% ,
        システムコール 3.10s → 0.66s,
        暗号化演算 1.6s → 0.11s,
        帯域幅 6.5Mbit/s → 3Mbit/s
    • 性能が50%以上向上

LLMを活用したデバッグ経験

  • Claude Codeを使って tcpdumptshark の分析を自動化し、問題の原因を迅速に絞り込み
    • コマンド実行の過程をリアルタイムで観察しながら、メンタルモデルの維持が可能
  • ChatGPTはSSHの動作を「正常」と誤って判断するなど、モデル間の違いも経験
  • LLMが問題解決の全工程を置き換えるわけではないが、補助分析ツールとして高い効率性を示した
  • 人間の推論とLLMの分析を組み合わせて、複雑なネットワーク性能問題を解決した事例

1件のコメント

 
GN⁺ 2026-01-23
Hacker Newsのコメント
  • Goのcryptoライブラリをforkするのは少し怖く感じる。
    自分の小さなパッチを安全に保つ方法を考えている。
    正直、こういう機能はsshライブラリのオプションとしてupstreamされるべきだと思う。
    信頼できない環境ではchaff(ノイズ)パケットを送るのをデフォルトにするのがよいが、帯域幅を節約したい場面も多い。

    • 機能をアドバタイズしないやり方で制御するのは、あまりに不安定なアプローチだ。
      サーバーがクライアントに「不要だ」というシグナルを送れるオプションを追加し、クライアント側はそれを受け入れるか警告するようにするのが正しい解決策だ。
    • 実際、すでに似たような挙動はある。
      TTYセッションでのみ適用され、クライアントが無効化できる。
      ただ今回は、サーバーがあらかじめ重要ではない接続だと分かっているために生じた例外的なケースだ。
      ほとんどの場合、クライアントはObscureKeystrokeTiming設定が守られることを期待する。
    • それでも、この変更は却下される可能性が高いと思う。
      cryptoライブラリは非常に意見の強いコードベースで、TLS cipher suiteの順序すら変更できないようになっている。
    • 信頼された環境でも脅威は存在する。
      これはSSHのかなり特殊なユースケースに見える。
      あまり広く公開すると、「設定して忘れる」状態になって逆にセキュリティを弱めるかもしれない。
    • 昔は1KB RAMのZX80を使っていた時代があった。
      1200bpsモデムで通信していた頃もあり、56Kモデムは実際にはかなり誇張だった。
      1994年ごろにはイギリスの軍事大学で働きながらWWWに初めて触れたが、そのときは「いまいちだな」と思った。
      今思うと本当に時代の変化には驚かされる。
  • このobfuscation機能は初めて知ったが興味深かった。
    sshの挙動をデバッグするときは、「None」cipherをパッチしてパケット内容を直接見るのもよい方法だ。
    セキュリティが重要ではなく性能が重要なターミナルゲームなら、単にtelnetを使うことも検討できる。

  • SSHがこういうことをしているとは知らなかった。
    デフォルトで有効なのは理解できるが、自分の環境では無効にするのがよさそうだ。

    1. SSHで秘密情報を直接タイプすることはほとんどない。
    2. 国家レベルの攻撃者が自分のキーストロークをsniffingする理由もない。
    3. 大陸間接続なので帯域幅の節約が重要だ。
      だからObscureKeystrokeTiming=noに設定しようと思う。これをやるべきでない理由はあるだろうか?
    • 楽観的なセキュリティ姿勢は危険だ。
      (1) 人がいつ秘密を入力しているかを常に見分けるのは難しく、活動全体がパターン分析され得る。
      (2) これは大学の研究室レベルでも可能な攻撃だ — USENIX論文研究事例 を参照。
      (3) 動画トラフィックが支配的なインターネットで、キーストローク数バイトの節約のためにセキュリティを捨てるのは意味がない。
    • tty SSH接続でよく入力する秘密はsudoパスワードだ。
      攻撃者がキーストロークのタイミングを分析すれば、コマンドや暗号化されたパスワードのパターンを推定できるかもしれない。
      もちろんセッションキーは毎回異なるので復号は難しいだろうが、可能性はある。
      自分もほとんどのパスワードはパスワードマネージャーからコピーして貼り付けている。
    • どんな平文が漏れても攻撃者にとって無意味だと確信することはできない。
      ほとんどの人はSSHのセキュリティ機能を無効にしても何の問題もないと感じるが、それは単に運が良かっただけだ。
      本当に性能が必要ならTelnet、本当にセキュリティが必要ならContainerSSH + OAuth2の組み合わせを使うのがよい。
  • 2004年にSSHセッションのキーストローク間隔分析でコマンドを推定する研究をしていた。
    当時の分析資料 を参照。
    2023年のパッチがついにその問題を解決したわけだ。

    • HAL2001ハッキングカンファレンスでDug SongSolar DesignerがSSHタイミング分析を発表していたのを覚えている。
      発表資料
      本当に時が経つのは早い。
  • Claudeがデバッグに実際どれほど役立ったのかはよく分からない。
    著者はすでに方向性を分かっていて、Claudeはただ相槌を打っていただけに見えた。
    Claudeが「Holy Cow!」みたいなことを言うのは少し鼻につく

    • それでもRubber Duck Debuggingのように考えを整理する助けになったなら価値はある。
      自分もClaudeでシステムの挙動をデバッグするとき、直接の答えはなくても理解の整理とモチベーション維持には役立つ。
      Rubber Duck DebuggingのWiki
    • Claudeはpcapフィールド抽出やawk処理の速度が自分よりずっと速い。
    • AIはテキストから性格を検知するのが得意だ。
      著者が「holy cow」という反応を気に入ってブログに入れたのを見ると、Claudeは雰囲気をよく読んでいたようだ。
    • 開発ツールに人格を与えるのは、良い考えではなかったのかもしれない。
  • TCP_CORKを使えば、遅延なしでパケット数を減らせる。
    TCP_NODELAYを無効にするのも方法だが、その代償として遅延の増加がある。

    • TCP_CORKは初めて聞いたが興味深い。
      ソケットをcorkすると、カーネルがデータをバッファリングし、uncorkするかMSSに達した時点で送信する。
      つまり、パケットをまとめて送る方式だ。
      参考資料
    • TCP_CORKを知らなかったが、本当に便利そうだ。
      pingはそのまま受けるだろうが、pongの送信回数は減らせそうだ。
      TCP_NODELAYはすでに使ったことがあるが、遅延が大きくなって自分のゲームには合わなかった。
      以前のHN記事
    • ただ、chaffパケットは20ms間隔で送信されるので、TCP_CORKがそれをまとめられるかは疑問だ。
      obfuscationの目的上、**遅延の合体(coalescing)**は不可能そうだ。
  • 「The smoking gun!」という表現が面白かった。
    英語ネイティブではないが、Claudeがよく使うので初めて覚えた。
    今では本当に流行語のように広まっている

  • LLM依存は残念だ。
    これは単にWiresharkでパケットキャプチャを見れば、もっと早く解決できたはずだ。
    SSH dissectorはかなり成熟している。

    • 自分もLLMは好きではないが、WiresharkでSSHパケットを見ても大半は暗号化されたパケットばかりで、有用な情報はない。
      tcpdumpで1回のキーストロークだけをキャプチャしても、数百個の暗号化パケットが出てくる。
      結局、LLMのおかげで著者が面白いことを学び、共有したのだから意味はあった。
    • SSH dissectorは完璧ではない。
      NEWKEYSメッセージ以降はパースできず、none暗号化にパッチしてもフロー全体を完全には解釈できない。
      改善の余地はある。
    • 「Wiresharkを見れば済んだ」という態度はゲートキーピングのように聞こえる。
      ツールを活用して学ぶことにも十分価値がある。
    • SSHは名前からしてセキュアなプロトコルだ。
      単純なパケットキャプチャだけでは意味のある情報を得にくい。
    • 著者はSSHパケットアナライザーを知らず、代わりに**汎用ツール(LLM)**を使っただけだ。
      それのどこが不幸なことなのか分からない。
  • 2023年にSSHがキーストロークタイミング難読化機能を追加した。
    タイピング速度から文字を推定できるため、SSHはchaffパケットを混ぜて攻撃者が区別できないようにする。
    だが、これは間違ったアプローチのように思える。
    本当に必要なら、すべてのキーストロークを50ms間隔で送ればよい。

    • 50msの遅延は、入力体感としてかなり不快になりそうだ。
    • 50ms間隔で送るというのが、20msの代わりに50msへ変えるという意味なのか、それとも継続的に一定間隔で送信するという意味なのか曖昧だ。
      現在の実装は20ms単位でまとめつつ、一定時間入力がなければchaff送信を止める方式だ。
  • SSHの本質はセキュリティだが、セキュリティが不要ならなぜSSHを使うのか疑問だ。
    たとえばnetcat(nc) はたいていのプラットフォームに標準で入っている。

    • 「セキュリティが最優先」だからといって、それがすべてではない。
      SSHには性能や利便性など、他の考慮事項もある。
      著者が言っているのは単に**キーストローク難読化(privacy)**機能が不要だということだけだ。
      暗号化や完全性保証はなお維持したいのかもしれない。
      つまり、SSHのセキュリティ機能の大半はそのままに、一部だけ無効にするという選択だ。
    • Windowsにも今ではSSHが含まれているので、「すべてのプラットフォームにncがある」というのは正確ではない