WebOS Goodies

WebOS の未来を模索する、ゲームプログラマあがりの Web 開発者のブログ。

WebOS Goodies へようこそ! WebOS はインターネットの未来形。あらゆる Web サイトが繋がり、共有し、協力して創り上げる、ひとつの巨大な情報システムです。そこでは、あらゆる情報がネットワーク上に蓄積され、我々はいつでも、どこからでも、多彩なデバイスを使ってそれらにアクセスできます。 WebOS Goodies は、さまざまな情報提供やツール開発を通して、そんな世界の実現に少しでも貢献するべく活動していきます。
Subscribe       

SSH の仕組み

きんぐさんこちらの記事で SSH のホスト認証に関して疑問を投げかけておられました。

実は私も SSH 関係で大ポカをやってしまいまして、先日書き換えた PuTTY の記事に、公開鍵は安全でない経路で転送しても大丈夫、とか書いてしまいました。はい、改竄される可能性があるので、ぜんぜん大丈夫じゃないですね orz

そんなわけで、自分の頭の中を整理する意味も含めて、SSH の認証手順をまとめてみました。「SSH の仕組み」なんて大それたタイトルを付けてますが、単なる聞きかじりです。もし間違いなどありましたら、どうかご指摘くださいませ m(_ _)m

公開鍵暗号とは

まず最初に、SSH などで使用されている「公開鍵暗号」ってなんなのでしょう?

普通、私たちが「暗号」という言葉で思い浮かべるのは、ひとつの鍵でデータの暗号化と復号を行うものです。よくある、「アルファベットをある数だけずらして文章を書く」という暗号(?)では、いくつずらしたかが「鍵」なわけですね。こういう暗号を「共通鍵暗号」と呼びます。

これに対して、公開鍵暗号では「暗号化用の鍵」と「復号用の鍵」のふたつの鍵を使います。暗号化用の鍵で暗号化したデータは、復号用の鍵を使わないと復号できません。暗号化用の鍵だけでは暗号化はできても復号はできないのです。さらに、復号用の鍵から暗号化用の鍵を推測することも極めて難しいようになっています。このような性質があるので、データの送り主に暗号化用の鍵だけを渡してやれば、自分以外の誰にも復号できないように暗号化できます。暗号化されたデータは、送り主ですら復号することができません。

一般的には「暗号化用の鍵」のことを「公開鍵」、「復号用の鍵」のことを「秘密鍵」と呼びます。ここでも、今後はこの呼び方を使うことにしますね。

このようにとても便利な公開鍵暗号ですが、ひとつ欠点があります。それは、データの暗号化や復号にとても時間がかかることです。大量のデータ通信に使うのは現実的でないほど重いらしいです。そのため、 SSH では公開鍵暗号を使ってデータ通信で使うための共通鍵を送信し、実際のデータ通信は秘密鍵暗号を使って通信しています。つまり、公開鍵暗号が使われるのは一番最初だけなわけです。これも SSH を理解するうえでのポイントなので、覚えておいてください。

ホスト(サーバー)認証

クライアントが SSH サーバーに接続すると、最初に行われるのが問題のホスト認証です。これは接続しようとしているサーバーが正しいものであることをクライアントが検証するプロセスです。 SSH では、ホスト認証にはホスト鍵とサーバー鍵のふたつの鍵ペアを使います。ホスト鍵は基本的に変化せず、IP アドレスや DNS の詐称防止に使用されます。サーバー鍵は一定時間ごとに計算しなおされるので、毎回違います。これはセキュリティーを向上させるためでしょうかね。

これらを踏まえて、ホスト認証は以下の手順で行われます。

  1. サーバーがホスト公開鍵とサーバー公開鍵をクライアントに送信する。
  2. クライアントは、"~/.ssh/known_hosts" に登録されたデータと照合して、ホスト公開鍵が正しいかどうかを検証する(初回の接続のときはどうにもならないので、ユーザーに確認する)。
  3. ホスト公開鍵が正しければ、クライアントは以後の通信で使う共通鍵をランダムに生成し、ホスト公開鍵とサーバー公開鍵で暗号化してサーバーに送信する。
  4. サーバーはクライアントから受け取ったデータをホスト秘密鍵とサーバー秘密鍵で復号し、共通鍵を取得する。

もしサーバーがいずれかの秘密鍵を持っていなければ、クライアントから送信された共通鍵を復号できません。そんなわけで、正しいサーバーに接続していることが保証されるわけです。

ユーザー認証

ホスト認証をクリアしたら、次はユーザー認証です。これはホスト認証とは逆に、サーバーがクライアントの正当性を検証するプロセスです。これにはいろいろな認証方法がありますが、ここでは公開鍵認証に話を絞ります。

公開鍵認証は、実際には公開鍵暗号を使ったチャレンジ・レスポンス認証です。具体的な手順は以下のようになります。

  1. クライアントはユーザー名とユーザーの公開鍵をサーバーに転送します。
  2. サーバーは、クライアントの公開鍵が "~/.ssh/authorized_keys" に登録されているかどうかをチェックします。
  3. 登録されていた場合は、ランダムな値を生成し、クライアントの公開鍵で暗号化して送信します。
  4. クライアントは、受け取ったデータを自分の秘密鍵で復号し、その結果をサーバーに送り返します。
  5. サーバーは返送されたデータと暗号化前のデータを比較し、それらが等しければユーザーを認証します。

もしクライアントが秘密鍵を持っていなければ、サーバーが送信したランダムな値を正しく復号できず、正しいレスポンスを返すことは不可能なはずです。従って、クライアントが正当な秘密鍵を持っていることが保証されます。

この手順では、実際にネットワークに流れるのは公開鍵とランダムに生成された値だけで、ユーザーのパスワードも秘密鍵もまったく送信されません。これが、公開鍵認証が安全であると言われる所以です。もちろん、一連の通信はホスト認証のときに確立した共通鍵で暗号化されているので、もともと他のホストが盗聴することは困難です。

SSH2 でのホスト認証

ここまで書いたのは、実は SSH1 での手順です。SSH2 では、ホスト認証時に「鍵交換」という方法を使用することで、ネットワーク上に共通鍵をまったく流さずに共通鍵を確立します。

サーバーとクライアント双方で個別に乱数を生成し、それにある計算を施して別の値を算出します。その計算結果を互いに交換して、最初の乱数と組み合わせてさらに計算すると、あら不思議、双方とも同じ値が得られるんだそうです。しかも、この最終的に得られる値は交換した(ネットワークに流れた)値のみで推測するのは困難になっています。したがって、この値を共通鍵として使用することができます。

最早なにを言っているのか、自分でもさっぱりわかりません(´Д`;。まるで魔法のようですが、そういうことが可能なんだそうです。Diffie-Hellman というのが代表的なアルゴリズムだそうで、こちらこちらで詳しく解説されているので、興味のある方はどうぞ。

いやはや、暗号通信というのはホントに別次元の話ですね。なんか、ファンタジーの世界にいるような気がしてきます。ま、私のような凡人に理解できるようでは、暗号の意味がないかもしれませんが。この記事を書いていたら、OpenSSH に寄付しなきゃいけない気がしてきましたよ!(゜Д゜;

関連記事

この記事にコメントする

Recommendations
Books
「Closure Library」の入門書です。
詳しくはこちらの記事をどうぞ!
Categories
Recent Articles