SSHとは?仕組みと安全な接続方法を解説
SSHはリモートサーバーへ暗号化接続するプロトコルです。クライアントとサーバーの役割、標準ポート22、host key fingerprint、鍵認証とパスワード認証の違いを解説します。
SSH とは
SSH(secure shell)は、暗号化された接続を通じて別の場所にあるコンピューターへログインし、コマンドを実行するためのプロトコルです。入力した内容はリモートマシンへ送信され、実行結果が戻ります。途中のネットワークを監視している第三者は、どちらの内容も読み取れません。レンタルした Linux サーバーには画面もキーボードも接続されていないため、SSH がそのマシンを利用するための手段になります。
この名称は2つの意味で使われます。SSH は RFC 4251 から RFC 4254 で定義されたプロトコルです。OpenSSH はそれを実装するプログラムで、ほぼすべての Linux サーバーと、ほぼすべてのラップトップで実際に動作しています。「サーバーへ SSH で接続する」とは、自分のマシン上のクライアントプログラム ssh が、接続先のサーバープログラム sshd と通信することを意味します。
SSH が置き換えるために作られた問題
リモートログインは SSH よりはるか昔から存在していました。Telnet はポート 23 への平文の TCP 接続を確立し、入力されたすべてのバイトをそのまま送信していました。暗号化は一切なく、パスワードも例外ではありませんでした。通信を見られる人なら誰でも内容を読めました。同じオフィスネットワーク上にいる人や、経路上のルーターを運用する担当者などです。rlogin 系も同じ弱点を持ち、クライアントマシンを名前で信頼していました。つまり、ネットワークがその名前として主張する対象を無条件に信頼していたということです。
Tatu Ylönen は、大学ネットワークでパスワードの盗聴攻撃が発生した後、1995 年に Helsinki University of Technology で最初の SSH を開発しました。この設計は、端末とリモートシェルの間でバイトストリームをやり取りするという Telnet の有用な部分を維持し、Telnet では解決できない 2 つの問題に対応しました。ストリームの暗号化と、接続先のサーバーが本当に意図した相手であることの証明です。
後者は見落とされやすい点ですが、SSH の役割の半分を占めます。暗号化だけでは十分ではありません。中間者のマシンが接続を受け付け、通信を完全に暗号化したうえで、送信内容を読み取り、実際のサーバーへ転送することも可能だからです。SSH は、すべてのサーバーに host key と呼ばれる恒久的な識別情報を持たせ、接続するたびにそれを検証することで、この攻撃を防ぎます。
クライアントとサーバーのモデルの仕組み
プログラムは 2 つあります。サーバーでは sshd が常時実行され、接続を待ち受けます。ユーザーのマシンでは ssh が接続を開始します。これらは別々の設定ファイルを使用する別のプログラムです。両者を混同すると、編集内容が反映されないことが最も多くあります。
- サーバーは
/etc/ssh/sshd_configを読み込みます。ここでパスワードログインを無効にし、待ち受けポートを設定します。 - クライアントはまずシステム全体のデフォルトとして
/etc/ssh/ssh_configを読み込み、次にホストごとの独自設定として~/.ssh/configを読み込みます。
Debian と Ubuntu では、サービス unit の名前は ssh です。RHEL、Rocky、Fedora では sshd です。最近の Ubuntu リリースでは、socket activation によってサービスが起動する構成が採用されています。そのため、マシンに正常に接続できる場合でも systemctl status ssh が inactive (dead) と報告することがあります。待ち受けを担当しているのは ssh.socket であり、必要に応じてサービスを起動するためです。
クライアントは OpenSSH である必要はありません。Windows の PuTTY、スマートフォンの Termius、エディターに組み込まれたリモートサポート機能も、同じプロトコルで同じ sshd と通信します。Windows 10 と 11 には OpenSSH クライアントも含まれているため、インストールなしで PowerShell から ssh you@server を使用できます。
SSH がポート 22 を使用する理由
ポートは、着信接続をどの待ち受けプログラムに渡すかをカーネルに知らせる番号です。Linux のポートは、どのサービスでも同じ仕組みで動作します。SSH が 22 を使用するのは、IANA が 1995 年に割り当てたためです。Ylönen は、SSH が置き換える予定だったプロトコルの近くにある未使用の番号を申請しました。21 は FTP、23 は telnet に割り当てられており、22 は未使用でした。
22 がデフォルトであるため、あらゆるものが 22 を前提にします。Git のリモート、バックアップスクリプト、プロバイダーのコントロールパネルは、最初に 22 へ接続しようとします。インターネット上の自動スキャナーも同じです。パスワードログインを有効にした新しいサーバーは、起動から数分以内に /var/log/auth.log へ次のような行を記録し始めます。
Failed password for invalid user admin from 203.0.113.55 port 43122 ssh2このトラフィックは継続的に発生しますが、あなた個人を狙ったものではありません。sshd をポート 2222 に変更すると、このような行の大半を減らせます。スキャナーはサーバーを調査しているのではなく、22 番ポートでインターネット全体を走査しているためです。ただし、実際に対象を調べる攻撃者にとって、サーバーへの侵入が難しくなるわけではありません。ポート変更はノイズの削減と考え、それ以上の効果を期待しないでください。
ログインする前に、サーバーの応答を確認できます。
nc 203.0.113.10 22Ubuntu 24.04 では、SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13 に近い内容が表示されます。バナーは、暗号化が始まる前に平文で送信されます。双方がプロトコルバージョンに合意する必要があるためです。接続を閉じるには Ctrl+C を押します。
接続時にネットワーク上で発生すること
以下は、プロンプトが表示されるまでに 1 つの ssh you@server が実行する処理です。
- クライアントはホスト名を IP アドレスに解決し、ポート 22 への TCP 接続を確立します。
- 双方がバージョンバナーを平文で送信します。
- 双方が、対応するアルゴリズムの一覧を送信します。対象は鍵交換、暗号、メッセージ認証、圧縮です。ここでも内容は平文です。双方が対応する中で最も強力な方式が選択されます。
- 鍵交換を実行します。現在の OpenSSH は
curve25519-sha256を優先します。最終的に双方が同じ共有秘密を保持しますが、その秘密自体がネットワーク上を通過することはありません。そのため、通信全体を記録した第三者でも、後から共有秘密を導き出すことはできません。 - サーバーは、ホスト秘密鍵を使って鍵交換の結果に署名します。クライアントは、保存しているホスト公開鍵を使って署名を検証します。これにより、通信経路上の第三者がサーバーになりすますことを防ぎます。
- 暗号化を開始します。現在の OpenSSH では
chacha20-poly1305@openssh.comがデフォルトの暗号です。 - その後で初めて、クライアントがパスワードまたは鍵を使ってユーザーを認証します。ユーザー名とパスワードは暗号化されたチャネル内を通過します。
- クライアントがチャネルを開き、シェルを要求します。
この一覧の順序が、telnet との決定的な違いです。認証はチャネルの暗号化後、かつサーバーが自身の正当性を証明した後に行われます。そのため、パスワードがネットワーク上を平文で通過する瞬間はありません。
ネットワークを監視する第三者にも、分かる情報はあります。第三者には、クライアントの IP アドレス、サーバーの IP アドレス、ポート 22、双方の平文のバージョンバナー、各パケットの送信タイミングとおおよそのサイズが見えます。一方、ユーザー名、パスワード、コマンド、その出力は見えません。手順 1 のホスト名解決は SSH の一部ではなく、通常は秘匿されません。そのため、サーバー名を解決する DNS クエリ から、セッション自体が暗号化されていても、これから接続するマシンを推測される可能性があります。
ホスト鍵と、初回接続時に表示されるフィンガープリント確認プロンプト
openssh-serverをインストールすると、マシン用のホスト鍵ペアが生成され、/etc/ssh/に書き込まれます。たとえば、ssh_host_ed25519_keyとssh_host_ed25519_key.pubです。秘密鍵はサーバーの外部に出ません。公開鍵がサーバーの識別情報です。手順5の署名は、この公開鍵を基に検証されます。
新しいサーバーに初めて接続するとき、クライアントには比較対象がありません。そのため、次のように確認を求められます。
The authenticity of host '203.0.113.10 (203.0.113.10)' can't be established.
ED25519 key fingerprint is SHA256:E9nVQ5Sm2oQ3nGm5Zf1tOaU7Xh0k2p8bWc4dLrTvYxA.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?フィンガープリントは、ホスト公開鍵のSHA256ハッシュをbase64で表示したものです。目視で比較できる長さに収まります。yesと入力すると、その鍵が自分のマシンの~/.ssh/known_hostsに書き込まれます。同じアドレスへ次回以降接続すると、サーバーが提示する鍵と保存済みの鍵が比較されます。一致すれば何も表示されず、そのままプロンプトに進みます。
この仕組みは、初回使用時の信頼(trust on first use)と呼ばれます。ただし、その代償を正しく理解しておく必要があります。最初の接続時だけは、まだ確認したことのない鍵を受け入れるため、保護されていません。この差を埋めるには、別の経路でフィンガープリントを取得して比較します。多くのプロバイダーは、Webコンソールに表示されるブート出力にフィンガープリントを表示します。サーバー上で次のコマンドを実行して表示することもできます。
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pubこれにより、プロンプトに表示されたものと同じSHA256:文字列が表示されます。プロンプトの[fingerprint]という選択肢は、まさにこの用途のためにあります。想定するフィンガープリントを貼り付けると、サーバーが提示したものと一致した場合だけクライアントが処理を続行します。
DebianとUbuntuでは、known_hostsはデフォルトでハッシュ化されています。そのため、ファイルには判読可能なホスト名ではなく、|1|で始まる行が保存されます。ssh-keygen -F 203.0.113.10を実行すると、特定のホストのエントリを検索できます。
SSH でホストキーが変更されたと表示されるのはなぜですか?
遅かれ早かれ、次の長いメッセージに遭遇します。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!最後に Host key verification failed. と表示され、クライアントは接続を拒否します。また、Password authentication is disabled to avoid man-in-the-middle attacks. も表示されます。これは、未知のマシンにパスワードを入力することを防ぐためのチェックだからです。
緊急事態のように見えますが、ほとんどの場合はそうではありません。一般的な原因は次のとおりです。
- サーバーを再構築または再インストールしたため、
sshdが初回起動時に新しいホストキーを生成した。これが最も多い原因です。 - 1 台の VPS を削除して別の VPS を作成し、プロバイダーが新しいマシンに以前の IP アドレスを割り当てた。
- フォワーダーまたはロードバランサー経由で接続しており、現在は別のバックエンドマシンに到達している。
- 実際に接続が傍受されている。
削除する前に、どの原因かを判断してください。10 分前にマシンを再インストールしたのであれば、原因は明らかです。自分の側で何も変更していない場合は、停止して調査してください。この警告は、チェックが正しく機能していることを示しているためです。問題がないと確信できたら、古いエントリーを削除して再接続します。
ssh-keygen -R 203.0.113.10次回の接続では、フィンガープリントの確認プロンプトが再び表示されます。プロバイダーのコンソールに表示された値と比較する新たな機会になります。
パスワードログインと鍵ログインの比較
パスワード認証では、すでに暗号化されたチャネル内でパスワードを送信し、sshd が通常は PAM(プラグ可能認証モジュール)を介してアカウントデータベースと照合します。準備は不要です。そのため、プロバイダーは root パスワードだけを設定した新しいサーバーを提供できます。
弱点は暗号化ではありません。パスワードは短い秘密情報であり、ログインのたびにサーバーへ送信されます。また、22 番ポートは、疲れを知らないマシンによって常時推測攻撃を受けています。
公開鍵認証は仕組みが異なります。自分のマシンで鍵ペアを作成します。公開鍵を、サーバー上のアカウント内にある ~/.ssh/authorized_keys に登録します。秘密鍵は自分のラップトップに保持し、送信することはありません。ログイン時、クライアントは鍵交換で得たセッション識別子を含むデータに署名し、サーバーは保持している公開鍵を使って署名を検証します。署名対象のデータはこのセッションに結び付いているため、取得された署名を別の接続に悪用することはできません。
方向を間違えないでください。逆にすると、よくあるうえに危険です。公開鍵はサーバーに置き、秘密鍵は自分で保持します。サーバーにコピーした秘密鍵は、もはや信頼できる秘密鍵ではありません。
鍵ログインにも固有の失敗原因があります。ファイル権限が緩すぎると sshd は鍵を無視し、そのことをサーバーログに記録します。
Authentication refused: bad ownership or modes for directory /home/ubuntu/.sshクライアントが表示するのは Permission denied (publickey) だけです。このメッセージは十数種類の異なる原因で表示されます。そのため、締め出される前に公開鍵エラーを正しく読む方法を学んでおく価値があります。鍵の作成、パスフレーズによる保護、エージェントへの読み込みといった実際の作業については、SSH 鍵管理を参照してください。自分を締め出さずにパスワードログインを無効化する方法については、VPS 上の SSH を堅牢化するを参照してください。
SFTP、scp、ポートフォワーディングは同じ接続を使用します
ここを理解すると、SSH の仕組み全体が整理しやすくなります。認証によって暗号化された接続が確立され、その接続で複数の独立したチャネルを同時に使用できます。シェルは、複数あるチャネルの種類の1つです。
- リモートシェル。
ssh you@serverはセッションチャネルを開き、対話型シェルを要求します。 - 単一のコマンド。
ssh you@server uptimeはチャネルを開いて1つのコマンドを実行し、出力を表示して終了します。 - SFTP。クライアントは
sshdにsftpサブシステムを起動するよう要求し、ファイル転送を同じ接続内で実行します。SFTP は SSH 上で動作するファイル転送プロトコルであり、FTP とは設計上の共通点がありません。FTP に暗号化を追加したプロトコルは FTPS と呼ばれ、SFTP とは無関係です。 - scp。同じログイン情報を使ってファイルをコピーします。2022年にリリースされた OpenSSH 9.0 以降、
scpはデフォルトで内部的に SFTP プロトコルを使用します。 - ポートフォワーディング。
ssh -L 8080:localhost:80 you@serverはラップトップのポート 8080 を、暗号化された接続を通じてサーバーのポート 80 へ接続する入口にします。-Rは逆方向に転送し、-D 1080はセッションを SOCKS プロキシとして動作させます。 - Git。
git@github.com:user/repo.gitのようなリモートは SSH ログインであり、リモート側ではシェルの代わりにコマンドハンドラーが実行されます。 - rsync と Ansible も SSH クライアントです。チャネルを開き、処理を実行して、出力を読み取ります。
この一覧にあるすべての項目は、同じポート、同じホストキーの確認方法、同じ認証情報を使用します。そのため、鍵認証を一度設定すれば、すぐに効果が得られます。これらのツールがすべて設定を引き継ぐためです。また、同じ ~/.ssh/config ファイルがログインを短縮するだけでなく、1台のラップトップから複数の Linux サーバーを管理する場合にも役立つ理由でもあります。
SSH でできないこと
- サーバー自体を安全にするわけではありません。SSH が保護するのは、ドアまでの経路です。ドアは存在したままであり、誰かが取っ手を試し続けます。fail2ban による繰り返しログイン試行のブロックで試行回数に対処し、鍵のみの認証で推測される対象をなくします。
- 自分のマシンから保護してくれるわけではありません。ノートパソコンにアクセスできる人は、秘密鍵と読み込まれた agent を取得できます。
- SSH を使用している事実を隠すわけではありません。ポート番号と平文のバージョンバナーによって、SSH の使用が示されます。
- 接続が確立する前の処理は対象外です。名前解決と、どのアドレスを信頼するかの判断は、いずれも接続に先行します。
ここから先に進むには
現在、プロバイダーのコンソールで新しいサーバーを開いている場合は、進める順序が決まっています。まずログインし、通常のユーザーを作成して、鍵を登録します。その後、簡単に侵入できる経路を閉じます。新しい VPS で最初の 10 分に行うことでは、その手順を最初から最後まで説明しています。用語がまだ馴染みのない場合は、VPS の実体で、その下で動作するマシンについて確認できます。その後は、鍵と hardening の 2 つの記事を、この順序で読んでください。
FAQ
SSH は何を意味しますか?
SSH は secure shell を意味します。暗号化された接続を使用してリモートコンピューターにログインし、コマンドを実行するためのプロトコルです。RFC 4251 から RFC 4254 で定義されています。ほぼすべての環境で使用されている実装が OpenSSH です。手元のマシンでは ssh クライアントを使用し、リモートマシンでは sshd サーバーを使用します。SSH は telnet に取って代わりました。telnet はパスワードを含むすべての情報を平文でネットワーク上に送信していました。
SSH が port 22 を使用するのはなぜですか?
IANA は 1995 年に SSH へ port 22 を割り当てました。SSH が置き換えるために作られたプロトコルである FTP の 21 と telnet の 23 の隣です。この番号が必須というわけではありません。サーバーでは /etc/ssh/sshd_config の Port で変更でき、クライアントでは ssh -p で別の番号を指定できます。22 がデフォルトであるため、自動スキャナーは常にこのポートへ接続を試みます。そのため、新しいサーバーでは /var/log/auth.log に Failed password for invalid user の行が大量に記録されます。ポートを変更するとこのノイズは減りますが、実質的な保護にはなりません。
SSH がホストキーの変更を警告した場合、どうすればよいですか?
何かを削除する前に、原因を確認してください。よくある無害な理由は、サーバーが再構築され、sshd が新しいホストキーを生成したことです。新しいマシンに以前の IP アドレスが割り当てられた場合もあります。マシンが再構築されたことを把握している場合は、ssh-keygen -R <host> を実行して保存済みのキーを削除し、再接続してください。その後、表示されたフィンガープリントと、プロバイダーのコンソールに表示されるフィンガープリントを比較します。自分の側で何も変更していない場合は、接続せず、パスワードも入力しないでください。OpenSSH はまさにこの理由から、この状態ではパスワード認証を拒否します。
SFTP と scp は SSH と異なりますか?
SFTP と scp は SSH 上で動作します。認証が完了すると、SSH 接続では複数のチャネルを使用できます。シェルはそのうちの 1 つにすぎません。SFTP は、同じ接続上で sshd の sftp サブシステムを使用するファイル転送プロトコルです。scp は OpenSSH 9.0 以降、内部で SFTP プロトコルを使用しています。ポートフォワーディングと SSH 経由の Git も、同じ接続上のチャネルです。これらはすべて同じポート、同じホストキー検証、同じログインを使用します。SFTP は暗号化を追加した FTP ではありません。暗号化された FTP は FTPS と呼ばれ、別のプロトコルです。
キー認証は本当にパスワードより優れていますか?
はい。インターネットから到達可能なサーバーでは、キー認証の方が優れています。パスワードは、ログインのたびにサーバーへ渡す短い秘密情報です。port 22 には自動クライアントが継続的にログインを試みます。キーペアを使用すると、秘密鍵は手元のマシンから外に出ません。クライアントが現在のセッションに関連付けられたデータへ署名し、サーバーが ~/.ssh/authorized_keys に登録された公開鍵でその署名を検証します。記録された署名を別のサーバーに対して再利用することはできません。秘密鍵はパスフレーズで保護してください。パスフレーズのないキーファイルは、それをコピーした人がそのままログインに使用できるためです。