SSHログイン時の認証方式(パスワード認証・公開鍵認証)についての考察です。
目次
公開鍵暗号
公開鍵認証の前に公開鍵について。
まず大雑把に、暗号化の方法には下記のようなものがあります。
- 共通鍵方式
- 暗号化、復号(暗号化されているものを元に戻すこと)に同じ鍵を利用する暗号化方式。
例)ZIPで利用するパスワードなど - 公開鍵方式
- 事前に用意した1対の鍵(キーペア、一般的にそれぞれを秘密鍵・公開鍵という)を利用した暗号化方式。割符のようなイメージ。
[note]公開鍵方式の暗号はどちらの鍵を使っても暗号化できるものが多いですが、片方が暗号化用、片方が復号用となっている暗号方式もあります。
が、今回は話がややこしくなるので、ここでは(RSA方式をイメージして)どちらでも暗号化できるものとして。[/note]
例えば、公開鍵で暗号化したデータの復号にはその対となる秘密鍵が必要となります。
秘密鍵で暗号化したデータの復号にはその対となる公開鍵が必要となります。
一般に公開鍵方式で暗号化されたデータは、データを受け取る側の鍵が安全に管理されていれば安全性が担保されるます。
そのため、受け取る側の鍵を「秘密鍵」としてセキュアに保管し、送る側の鍵を「公開鍵」として必要に応じて一般公開・共有して構いません(ので「公開」鍵)。
[tip]
キーペアの一致が前提となるため、それを利用してお互いの認証を行うことにも利用されます。
また、同じような利用方法として「電子署名」があります。
(本人しか持っていないはずの秘密鍵で署名すると、公開されているその人の公開鍵で本人性が確認できる。)
[/tip]
[note]
※余談
SSLで利用される「SSL証明書」は「署名付き公開鍵」です。
参照→ SSL証明書について。 )
[/note]
パスワード認証
パスワード認証の場合、クライアントがサーバに接続する手順は以下のようになります。
- クライアント(C)→サーバ(S):接続するユーザ名とパスワードをサーバに通知
- S:そのユーザに設定されているパスワードと一致していた場合、認証成功
SSHの場合そもそもの通信経路が既に暗号化されているとはいえ、ネットワーク上をパスワード自体が流れることが注意点です。
公開鍵認証
OpenSSHで公開鍵認証を利用する場合、秘密鍵をクライアント側、公開鍵をサーバ側の所定のディレクトリ(デフォルトはユーザのホームディレクトリ/.ssh/authorized_keys)に設置します。
クライアントがサーバに接続する手順は以下のようになります。
- クライアント(C)→サーバ(S):接続するユーザ名をサーバに通知
- S→C:ランダムな文字列をそのユーザに対応する公開鍵で暗号化したデータを送信
- C:上記の暗号化されたデータを、自分の秘密鍵で復号市、元のランダム文字列を取り出す。
- C→S:上記で取り出したランダム文字列をハッシュ(md5やsha1のような)した文字列を送信
- S:元のランダムな文字列をハッシュしたものと、送られてきた文字列が一致した場合、認証成功
ポイントは、パスワードのような直接認証に利用されるデータがネットワーク上を流れないこと、です。
また、サーバ管理者(設定者)すらユーザの認証情報を持たない(公開鍵だけでは認証できない)ことも特徴になります。
利用される文字長が、多くのパスワードで利用する文字数よりも長いので、総当たり的な攻撃に対しても強くなります。
[warning]
リスクは秘密鍵の漏洩です。
リスク軽減策は、秘密鍵にパスフレーズを設定すること、になりますが、充分に長いなどパスワードの強度に求められる内容と同じレベルでのパスフレーズ選定が重要になります。
[/warning]
また、1つのユーザに複数の公開鍵を設定することもできますが、実際の接続時に利用された公開鍵が誰のものかが分かりにくくなるため、複数人で1アカウントを共用することは推奨できません。
※ただし、外部ベンダー用に特定のアカウントを作成し、その公開鍵として実際のユーザ(人)分を設定、その人が接続する必要がなくなったら対応する公開鍵を削除する、といった利用方法は想定できます。
ベンダー用に1つの公開鍵を貸与するよりは管理しやすい、という意味で。
[tip]
※ /etc/ssh/sshd_config に 下記の設定をすることで、ログに認証時に利用された公開鍵のフィンガープリントが記録されます。
LogLevel VERBOSE
公開鍵のフィンガープリントは下記で確認できます。
ssh-keygen -l Enter file in which the key is (/root/.ssh/id_rsa): [確認したい公開鍵のパスを入力]
ただし、最初の1行についてのみ表示されるので、複数の公開鍵を設定したauthorized_keysをそのまま指定、とかはできません。
[/tip]
セキュリティレベルの比較検討
SSHは通信経路自体が暗号化されているという点において、通信経路上にパスワードが流れるとしてもそれ自体がリスクとは言いきれません。
(ないにこしたことはない、という次元)
※実際に利用されるパスワードの文字長が現実的には数文字程度であることを踏まえると、公開鍵認証で利用される文字長は圧倒的に長いため、それ自体の解析難易度は高まっているとは言えます。
むしろ運用方法自体がセキュリティレベルに影響する要素と考えられます。
ポイントは、
- 認証情報を共有する人数(≒漏洩リスク)
- ユーザの増減への対応(管理リスク)
辺りになると思います。
パスワード認証の場合、同一アカウントを利用する全てのユーザが同一のパスワードを知ることになります。
人数が多いということはそれ自体が漏洩の可能性を増すことでもあり、また通知する必要があるということでもあるため、これもまた漏洩リスクを抱えることになります。
ユーザが減った場合、そのユーザが利用できなくするためにパスワードの変更が必要であり、変更後のパスワードを通知する際にまたリスクが発生することになります。
公開鍵認証を利用する場合、必要なのはユーザが自身で作成したキーペアの公開鍵であり、そもそも公開を前提としている情報であるためこれが漏洩したとしてもそれ自体がセキュリティリスクとなることはありません。
また、秘密鍵のパスフレーズはクライアント側でのローカル処理であり、通信経路上に流れるわけではないため、これもまたユーザ自身で完結するリスクになります。
ユーザの増減は、作業的には公開鍵の追加・削除であり他の既存ユーザへの影響はありません。
このあたりを踏まえると、公開鍵認証を利用する方がセキュアであるといえると思います。
なお、SSHのパスワード認証を無効化することを合わせて実施しないと効果は半減すると思います。
余談:接続しているサーバの真性について( known_hosts との関係)
SSHのサーバ側には、サーバ自体の真性を担保するためのキーペアが設定されています。
( /etc/ssh/ 以下にある ssh_host_* ssh_host_*.pub です。)
SSHでの接続をする際、接続するサーバからこの公開鍵の提示があります。
クライアント側では事前に保持している公開鍵リスト(known_hosts)と突き合わせることによって、自分が接続しようとしているサーバが間違いなく正しいものである(セッションハイジャックなどされていない)ことを確認できます。
仮想サーバを利用している場合、サーバイメージをコピーして利用することがあると思いますが、その際に /etc/ssh/ssh_host_* をそのままにしてしまうと、複数のサーバが同一のキーペアを持つことになり、それぞれの識別ができなくなってしまいます。
(広義ではキーペアの漏洩です。)
キーペアが作成されていない状態でsshdサービスを起動すると自動的にキーペアが作成されますので、上記のようなサーバ構築を行った場合は
rm /etc/ssh/ssh_host_* service sshd restart # CentOS系の場合
を実行することを手順化すべきです。
おまけ
UseDNS
CentOSの場合、 /etc/ssh/sshd_config の UseDNS はデフォルトでコメントアウトされており、デフォルト値は yes となっています。
これは、SSH接続してきたクライアントのIPアドレスの逆引きを試みるという設定なのですが、失敗したとしても接続できるものなのでセキュリティ上の強化にはつながっておらず、逆引きができない端末からの接続はタイムアウト(=逆引き失敗)するまで接続を待たされることになります。
UseDNS no
を追記することにより、逆引きを試みなくなります。
AddressFamily
同様に、AddressFamilyもコメントアウトされておりデフォルト値は any ですが、これにはIPv6も含まれるため、IPv6接続を想定しない環境にとっては無意味(かつ場合によってはセキュリティホール)なものです。
AddressFamily inet
を追記することによりIPv4のみが有効になり、IPv6でのLISTENをしなくなります。