はじめに
仲冬の候、皆様いかがお過ごしでしょうか。 KMCの電気工事士possum(ぽっすむ)です。 最近はコンセントを増やして過ごしています。
この記事はKMCアドベントカレンダー2013の8日目の記事です。 昨日の記事はdisさんのDungeon Crawl Stone Soup のソースを読んでみる話 - The Hand of Doomでした。
本日より10日間はKMCアドベントカレンダー2013のサブプロジェクトであるSSHアドベントカレンダー2013の記事が続きます。 日頃SSHに親しんでいる部員による、SSHの基礎知識、ツール、Tips等を紹介して参りますので、初心者の方から上級者の方までご笑覧いただければ幸いです。
SSHアドベントカレンダー2013の初回の今日は指紋(fingerprint)のお話をします。
このサーバがあなたの期待するコンピュータであるという保証はありません。
学部1回生の僕がKMCに入会してまだ間もない頃、 部室のサーバにSSHしようと大学に上がって買ってもらったPCに入れたPuTTYで部員用wikiの情報を見ながらホスト名を入力し意気揚々と「開く」ボタンを押したところ、 ターミナルに1文字も入力する前にこのような警告画面が出現し、 初めてSSHした僕はこのダイアログを前にしてしばし固まってしまいました。
このサーバの鍵はレジストリにキャッシュされていません。
このサーバがあなたの期待するコンピュータである という保証はありません。
このサーバのrsa2鍵の指紋は次の通りです: ssh-rsa 2048 XX:XX:XX:……
このホストを信用するのであれば、「はい」を押して PuTTYのキャッシュに鍵を追加し接続してください。
キャッシュには追加せずに一度だけ接続したいので あれば、「いいえ」を押してください。
このホストを信用しないのであれば、「キャンセル」 を押して接続を破棄してください。
このメッセージの意味がわからなかった僕はその時ちょうど部室にお見えだった disさんに、このように警告されているのですが「はい」を押せば良いのでしょうかと 尋ねたところ、意味を理解した上で「はい」を押すように、と助言されたのをおぼえています。 またその後、意味を理解せずに「はい」を押したこともおぼえています。
そこで今日はこの警告が何に警鐘を鳴らしているのかを解説したいと思います。 SSH初心者の皆さんの心の平穏の一助になれば幸いです。
SSHの共通鍵暗号と公開鍵暗号
今回お話しするSSHサーバはパスワード認証を採用しているものとします。
あなたがサーバにSSHするとユーザ認証のためにユーザ名とパスワードを求められます。 ここであなたはパスワードをサーバに送らなければならないのですが、 パスワードが運ばれる道は魑魅魍魎の跋扈する殺伐とした世界であるインターネットを通っています。 途中にあなたのパスワードを傍受する輩がいないという保証はどこにもありません。
SSHと同じくサーバに接続するプロトコルであるTelnetはパスワードになんの保護も施さずに送り出すので、 これを傍受してパスワードの持ち主になりすますということがいとも簡単にできます。
そこでSSHではパスワードを含む全ての通信内容を暗号化することで、 傍受されても簡単に中身がわからないようにします。
ここで2つの暗号が登場します。 1つは共通鍵暗号です。 これはメッセージを届けたい人と受け取りたい人の両方が同じ鍵を持つ暗号化方式です。 2人だけしか持っていない鍵でメッセージを暗号化すれば通信の途中で傍受されてもそう簡単にはメッセージの内容がわかりません。
ではこれでパスワードを送れば、と思いますがそうは問屋が卸しません。
共通鍵暗号を使ってあなたがサーバに暗号化したパスワードを送るには、
あなたとサーバで同じ鍵を持っておく必要があります。
この鍵をあなたが作ったとして、どうやってサーバに送ればよいのでしょうか。
インターネットにそのまま送り出してしまっては、鍵を傍受されてしまえばあなたとサーバの間の通信は筒抜けです。
従って、この鍵を安全にサーバに送り届ける方法が必要になります。
従って、あなたとサーバだけの秘密の共通鍵を共有する方法が必要になります。
そこで2つ目の暗号である公開鍵暗号を使います。 公開鍵暗号というのは、公開鍵と秘密鍵という対になる2つの鍵を使う暗号です。 公開鍵暗号は次の性質があります。
- 公開鍵で暗号化したものは秘密鍵でしか復号できない(公開鍵と秘密鍵を入れ替えても成り立つ)。
- 公開鍵から秘密鍵を作ることは現状不可能と言って良い。
SSHにおいてはこの性質を利用し、サーバが鍵対を作り、その内の公開鍵をあなたに送ります。
あなたはこの公開鍵を使って先ほどの共通鍵を暗号化し、サーバに送ります。
サーバは鍵対の内の秘密鍵でこれを復号し、共通鍵を得ます。
これであなたとサーバが安全に共通鍵を共有できました。
以降の通信は全てこのように共有した共通鍵で暗号化されます。
公開鍵が傍受されても、公開鍵で暗号化したメッセージは対になる秘密鍵でしか復号できないので公開鍵から秘密鍵を作ることができない限りメッセージの内容が漏れることはありません。
そして公開鍵から秘密鍵を作ることはとても難しいのです。
誰かから秘密のメッセージを受け取りたい時、 その相手に公開鍵を送ってこの鍵で暗号化してもらい、 自分は手元にある秘密鍵で復号する、というような使い方をします。
さて、SSHにおいてはこの公開鍵暗号の考え方を元にした 「Diffie-Hellman鍵交換」という方法が共通鍵の共有に用いられています。 この方法ではあなたもサーバも共通鍵そのものを相手に送りません。
まず、あなたとサーバでこの鍵交換を使うための「取り決め」をします。 ここは暗号化されている必要はありません。 次に、あなたとサーバはそれぞれランダムな値を作ってこれを鍵とし、 先ほどの取り決めと公開鍵暗号の方法に基づき暗号文を作り、これを交換します。 最後に、あなたとサーバは相手から送られてきた暗号文と自身が先に作った鍵で共通鍵を作ります。 するとなんと2人の作った共通鍵は同じになっているのです。
公開鍵暗号の性質により、「取り決め」と暗号文を傍受できたとしても、 あなたとサーバがそれぞれに作った鍵を求めることはとても難しく、 傍受しただけでは共通鍵を作ることは現状不可能と言って良いです。
公開鍵の指紋
さて、これで安心できるかと思えば残念ながらそうではありません。 ここでPuTTYの警告を思い出しましょう。
このサーバがあなたの期待するコンピュータであるという保証はありません。
あなたが共通鍵を共有したサーバは果たして「あなたの期待するコンピュータ」だったのでしょうか。 もしかしたら別の悪意ある人物の用意した偽のサーバかもしれないのです。
従ってあなたは共通鍵を共有する前に、接続しようとしているサーバが期待するコンピュータなのかどうか確かめなければなりません。 そこで、サーバから送られてくる暗号文が期待するサーバのものかどうか確認しようと思います。
サーバはあなたに確認してもらうために、暗号文に自身の作った公開鍵を付しています。 あなたはこれを事前にどこか信頼できるところで知った公開鍵と比較すれば良いのです。 しかしながら、利用される公開鍵はとても長く、おぼえるのはおろか、 同じかどうか確認するのも一苦労です。 ここで利用されるのが公開鍵の指紋(fingerprint)です。 指紋はこの公開鍵からハッシュ関数というものを使って作られます。 ここで言うハッシュ関数は次のような性質を持っています。
- 同じ入力に対する出力は常に同じになる。
- 異なる入力が同じ出力になることはとても稀である。
- 出力から入力を推測することがとても難しい。
また、SSHの公開鍵で使われる指紋はさほど長くはないので、 メモを取って比較することができます。 上記の性質のおかげで、指紋は公開でき、公開鍵が同じかどうかの確認に使うことができます。
期待するサーバの公開鍵の指紋をサーバの管理者から聞くなどして知ったあなたは、 共通鍵を共有する前にサーバから送られてきた公開鍵の指紋を採り、 先ほど聞いた指紋と比較します。 指紋が同じであれば、接続しようとしているサーバは期待するものである判断することができます。
このような「このサーバは期待するサーバか?」というような確認の他にも、 送られてきた暗号文が改ざんされていないかなどの確認を行うため、 公開鍵暗号の仕組みを利用した「ディジタル署名」 と呼ばれる技術も共通鍵の共有の手順の中で行われています。
警告の意味
冒頭の話に戻りましょう。 PuTTYさんは初めて接続するこのサーバが偽物でないか確認してきていました。 PUTTYさんはこのサーバを知らないので、公開鍵の指紋を提示し、 指紋を比較して期待するサーバか確認するよう僕に警告していたのです。 後にこの指紋を部内用のサイトで見つけることができました。
PuTTYやその他のSSHクライアントはここで一度「はい」を選択すると、 このサーバは主の期待するサーバであるとして公開鍵を覚えておいてくれるので、 以降同じサーバに接続する際にはこの警告を見ることはありません。
また、先の話ではあなたが共通鍵を作ると言いましたが、
実際にはSSHクライアントが生成してくれています。
公開鍵を見に行く
OpenSSHというSSHサーバの実装を採用したサーバであれば、 サーバの公開鍵は
cat /etc/ssh/ssh_host_rsa_key.pub
で見ることができます。 さらに、ssh-keygenというOpenSSHのコマンドの-lオプションを用いると指紋を見ることができます。 ※-fオプションはファイルを指定するオプションです。
ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub
また、SSHクライアントが覚えていてくれる公開鍵は 次の場所に記録されています。
- PuTTYの場合
- レジストリに書かれています。(HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys)
- レジストリエディタを使って見に行くことができます。
- OpenSSHの場合
- ホームディレクトリの下に.sshというディレクトリがあり、その中のknown_hostsというファイルに書かれています。
おわりに
SSH初心者の皆様、Next! Next! I agree! Yes! Yes! Install!の作業に慣れきった頭になる前に、 あのような警告を受けたら是非一度はサーバ管理者に指紋はどこに書いてありますかと尋ねてみるのが良いと思います。
長々と書きましたがこれでもかなりの部分が省かれています。 省かれている部分があるのがわかるようになるのに5年もかかっているのを思うとSSH力の足りなさを痛感します。
これで今回の僕の話はおしまいです。
明日はのな君がトンネルの掘り方を解説してくれます。
2013年12月18日追記
現在用いられているSSH Version 2.x においてはDiffie-Hellman鍵交換が用いられているとご指摘いただき、 記事を修正いたしました。