📝

実は7つの鍵が使われている!?|SSHの流れ・仕組み

2024/05/08に公開
1

この記事ではSSHがどんな流れで安全な接続を行なっているのかをざっくりと理解することを目的にまとめてみます。具体的なコマンドや接続するための手順ではなく、もう少し根本的なSSHという仕組み自体の話になります。SSH接続自体も全体を理解しようとすると結構複雑なのでまずはこの記事でざっくりイメージしてリンク先のページを参照していただくと理解が進むかな?と思います。

前提

VPSやクラウドなどのサービスを利用する場合での流れを説明しています。自分でUbuntuなどのLinuxOSをインストールしてサーバを構築する際にはもう少し手順が増えるので適宜調査してみてください。

学習の注意点|鍵の呼び方について

個人的にはSSHを調べていると鍵が様々な呼ばれ方をするのでよくわからなくなります。人間みたいなものですね。「日本人」「静岡県人」「社長」「お兄さん」「大人」など一人の人も場面によっていろいろな呼び方をされますが、鍵においてもそんなイメージがあることを最初に理解するのが結構大事だと思いました。そこでまずざっくりと機能についての呼び方と、役割についての呼び方があるのを整理してみます。

特徴的名称

「共通鍵」「公開鍵」「秘密鍵」これらは文字通りの特徴を持ちます。
共通鍵:クライアントとサーバが共通の鍵を持ちます。
公開鍵:公開しても良い鍵のことです。
秘密鍵:秘密にしなければならない鍵です。

使用用途を元にした名称

「ホスト鍵」「ユーザー鍵」「セッション鍵」これらは使用用途を表しています。
ホスト鍵:ホスト認証に使われます。
ユーザー鍵:ユーザー認証に使われます。
セッション鍵:セッション(通信)の暗号化に使われます。

そして実際の鍵は次のように複数の要素を持つ形で存在します。
「ホスト鍵の公開鍵」「ユーザー鍵の秘密鍵」
詳細は後述のイラストで見た方がわかりやすいと思いますのでまずはこんな呼び方があるんだな〜という理解で大丈夫です。

SSHとは

SSH(Secure Shell)とはネットワーク上のコンピュータに手元のハードウェアから接続して遠隔操作するための通信プロトコル、ソフトウェアです。よくサーバに接続して作業するなどと言われますがあれはSSHを使用していることが多いですね。

何に対してSecureか?

Telnetと比較すると
・通信データの盗聴
・通信相手のなりすまし
を防ぐ仕組み(通信内容の暗号化)を備えています。

SSHがSecureを確保するためにしていること概要

・セッション中の通信を暗号化(共通鍵)
・クライアントPCが通信相手を本物のサーバなのか確認(公開鍵と秘密鍵のペアその1。このペアはサーバ認証|ホスト認証に使われるのでホスト鍵と呼ばれます。)
・サーバが通信相手を本物のクライアントPCなのか確認(公開鍵と秘密鍵のペアその2、これがユーザー鍵と呼ばれます)
つまり通信する者同士それぞれが相手を確認しあって本物の通信相手かどうかを確かめています。
これによって安全に正確な相手と通信することが可能になります。

SSHの初期設定・接続する流れ

初期設定する流れですが「私たちが行う見える部分」と、「SSHコマンドがクライアントPCとサーバ(PC)との間で自動的に裏側で行ってくれている部分」がありますので大きく分けて解説します。

私たちが行う部分

1.クライアントPCで秘密鍵、公開鍵を作成します。これがユーザー鍵と呼ばれます。


通常はssh-keygenコマンドで作成されます。これは後述するクライアント認証に使われる公開鍵と秘密鍵のペアその2です。この鍵はユーザー鍵と呼ばれることがあります。

2.接続したいサーバに公開鍵を保存します。


具体的には通常サーバの特定ユーザーの~/.ssh/authorized_keysファイルに追加されます。ここまでで事前準備は完了です。

3.クライアントからサーバへ接続したいという信号を送ります。(SSHコマンドですね)


コマンド例)ssh username@server_address
ここまでが私たちが手を動かすところになります。

SSHが自動的に行ってくれている部分|SSHプロトコルの安全な接続プロセス確立

以下はクライアントとサーバ側で自動的に裏側で動いてくれる内容を解説します。
ここも大きく3つに分かれます。

4.鍵交換(Key Exchange)


ここでDH鍵交換を用いて共通鍵(セッション鍵)をクライアントとサーバで共有します。この共通鍵はSSHセッションをセキュアに暗号化するために使用されます。DH鍵交換の詳細はこちらの記事をご確認ください。
※このセッション鍵は実は3つあるそうです。1つはクライアント→サーバの通信用。2つ目はサーバ→クライアントの通信用。3つ目は安全性チェックのために使われるとのことでした。ただこれらの鍵はファイルにはなっておらずメモリ上で管理され、通信が終わったら破棄されます。

5.サーバ認証|ホスト認証


クライアントが接続先のサーバが本物かを確認するプロセスです。sshコマンドで最初にフィンガープリントを聞かれるのもここでの認証プロセスの一つになります。このプロセスはサーバが持つ秘密鍵と公開鍵のペアその1(ホストキー)のうちの公開鍵をクライアントに提示しているということです。サーバ認証をすることで接続しようとしているサーバーが本物であることを保証します。また中間者攻撃、IPスプーフィング、DNSスプーフィング攻撃を防ぐことができるとのことでした。

6.クライアント認証|ユーザー認証


サーバ側から通信の相手が本物のクライアントかを確認するプロセスになります。ここでも公開鍵と秘密鍵のペアその2が使用されています。注意点としてはサーバ認証とはまた別のペアが使われていることになります。(前述の「1.クライアントPCで秘密鍵、公開鍵を作成します」で生成した鍵です)

これでSSH接続(ログイン)できるようになりました。
このあとはセッション(通信)が開始されコマンドなどでサーバを操作します。
そしてセッションを終了、またはタイムアウトするとセッションキーは削除されます。次回接続時には新しいセッションキーが生成されます。
ユーザー鍵、ホスト鍵は自分で更新しない限り同じものを使うという形になります。

もっと知りたい方へ

公開鍵認証が具体的にどんな動きをしているかを知りたい方

今回、公開鍵認証が2つの場面(ホスト認証とユーザー認証)で出てきましたが、具体的なデジタル署名を使った認証方法などは割愛しています。実はこの認証の動きも見てみると面白いので興味のある方は以下の記事がおすすめです。

https://zenn.dev/tetsu1008/articles/8027cbab954e5e

実際に鍵を見てみたい方

EC2で理解するためのハンズオンをまとめてみましたので実際にやってみると理解が進むかもしれません。

https://zenn.dev/isosa/articles/2dfe273e42c638

※上記記事では変更点が1つあります。前述の「初期設定する流れ」の1と2ではクライアントPC側で鍵のペアを生成していましたが、EC2側で生成する機能があり、それを使うことが多いと思いますのでそちらに変わっている点にはご注意ください。

ホスト鍵はどこからきたのか?

前述の流れでホスト鍵が突然現れたことが気になった方がいるかもしれません。クラウド、VPSなどのサービスでサーバを利用する際には多くの場合ホスト鍵がサーバを立ち上げると生成されているようです。EC2に関しては実際に上記の記事通り進めていただくと確認できるのでお試しください。
なので自分でUbuntuなどのLinux OSから組む場合はユーザー鍵と同じようにssh-keygenコマンドで生成する必要があります。

あとがき

私自身SSH接続は使っていましたが正直こういった詳細は理解しておりませんでした。この記事を書くきっかけになったのが基本情報技術者試験の過去問でサーバ認証とクライアント認証の問題が出てきて、解説を読んでもなんか理解できていない気がする。。。ということがあり、また普段からフィンガープリントの値を確認する時も疑問があり、調査を進めていたらなんとか腹落ちできました。

参考

https://zenn.dev/tetsu1008/articles/8027cbab954e5e

https://zenn.dev/tetsu1008/articles/1e3673ca1ece42

https://www.oreilly.co.jp/books/4873112877/

一次情報はあまり読み解けていませんが参考までに一応貼っておきます。

https://www.rfc-editor.org/rfc/rfc4251

https://www.rfc-editor.org/rfc/rfc4252

https://www.rfc-editor.org/rfc/rfc4253

special thanks chatGPT

Discussion

IWAMOTO KouichiIWAMOTO Kouichi

・通信データの盗聴
・通信相手のなりすまし
を防ぐ仕組み(通信内容の暗号化)を備えています。

もう一つ、「通信データの改竄」を防ぐ仕組みもありますね。
なぜか軽んじられる事が多いのですが、他の二つと同じくらい大事な機能です。

以下はクライアントとサーバ側で自動的に裏側で動いてくれる内容を解説します。
ここも大きく3つに分かれます。

SSHで鍵交換(Key Exchange)と呼ぶ処理は以下の事を行います[1]

  1. 利用アルゴリズムの決定
  2. 鍵交換プロトコルによる秘密の値の共有
  3. 鍵交換[2]が正しく行われたかの確認 (ホスト認証)
  4. セッションID, 各種セッション鍵等の導出

このように、ホスト認証は鍵交換の一部として行われます。また、ホスト認証では1や2で得た値を利用しますし、ホスト認証で使ったホスト公開鍵も利用して各種セッション鍵の導出が行われるように、ホスト認証は鍵交換の他の部分と密接に関わり合って行われます。
なので、「3つに分かれます」というように別の処理で有るように書かれるのは抵抗が有ります。
"鍵交換"を鍵交換プロトコルの実行の部分を指す意味で使っているのならば分かれるとするのもまだ判りますが[3]、その場合は共有するのは秘密の値一つだけになります。

4.鍵交換 (Key Exchange)

ここでいう"鍵交換"がDH鍵交換等の鍵交換プロトコルの事を指すのならば、前述したように共有する値は一つだけです。

ホスト認証も含めた鍵交換処理全体の事を指すならば最終的に複数の値が共有されますが、その数はここに有るように6つです[4]
この内IVについては通常は鍵とは呼ばないので数えないのはいいのですが、Encryption keyを方向別に数えているのに、同じように方向別に有るIntegrity keyを”安全性の鍵”と一つにまとめるのは数え方がおかしいと思います。

5.サーバ認証|ホスト認証

「公開鍵(ホスト鍵)をフィンガープリントとして提示します」と有りますが、実際に提示されるのはホスト公開鍵そのものです。
そもそもホスト公開鍵やそのフィンガープリントはサーバーに接続出来れば簡単に入手できる公開された物であり、提示するだけならば偽物のサーバーも行えます。
重要なのは一緒に送った署名がホスト公開鍵で検証できる事によって、対応する秘密鍵を所有しているのを証明する事にあります。
フィンガープリントを送ったのでは、このホスト公開鍵による検証が行えません。
また ~/.ssh/known_hosts にはホスト公開鍵が保存される事からもフィンガープリントを送っているわけでは無い事が判ると思います。

6.クライアント認証|ユーザー認証

図ではサーバー側からクライアント側に何らかの要求をするように書かれていますが、実際にはクライアント側が自発的にユーザー認証を要求し、サーバーはそれに対して結果を返すだけです。
極端な状況では、ユーザー側は認証要求を送らずに直接コネクションプロトコルの利用を要求する事もSSHプロトコルでは許されています[5]。(ただし一般的なSSHサーバーでは許可を返さないでしょうが)

クライアントが送るユーザー認証要求では、署名と共にユーザーの公開鍵も一緒に送り、サーバー側はその公開鍵がユーザーのauthorized_keysに登録されているか確認した上で署名を検証するというように、ホスト認証とは方向が逆なだけで本質的には同じ事を行っています。
なので図はホスト認証の処理の方向を逆にした物にするのが判りやすいと思います。

脚注
  1. 参考: RFC4253 7章および8章 ↩︎

  2. 鍵交換プロトコルだけではなく、利用アルゴリズムの決定等を含めた鍵交換処理全体(の内外部との通信部分)を指します。 ↩︎

  3. 鍵交換の終了とホスト認証の為のホスト公開鍵の送信が同じパケットなので、完全に分かれるとも言い難いですが。 ↩︎

  4. 他には鍵交換プロトコルで共有した秘密の値(shared secret)とそこから計算されるセッションIDも有ります。shared secretは鍵交換処理の外では使わない値なので気にしなくてもいいです。セッションIDはユーザー認証等でも使われる事が有りますが、鍵ではなく秘密のデータ扱いです。 ↩︎

  5. RFC4253 10章では、コネクションが確率した後にssh-userauthサービスだけではなくssh-connectionサービスを要求する事も許されています。 ↩︎