sshでStrictHostKeyCheckingをnoにすることの問題点

最近、業務でSFTPに関連するコードを書いた。そこで、認証時の確認やknown_hostsについて詰まったところがあった。対処法をググるとStrictHostKeyCheckingをnoにする解決策が散見されたが、セキュリティ的にいかにも問題がありそうな設定だ。この記事ではこの設定のどこに問題があるかを順を追って説明していく。

sshは接続先が初めて接続するホストの場合、確認を出す。

ssh接続を初めてのホストに対して行おうとすると、こんな感じの確認が出る。

The authenticity of host '〜' can not be established.
ECDSA key fingerprint is SHA256:〜.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

ここに書かれているfingerprintとは何なのだろう。

fingerprint = 公開鍵のハッシュ値

ここで表示されているfingerprintというのは、ホストの公開鍵をハッシュ化したものだ。ssh接続では公開鍵認証方式を採用しているが、公開鍵認証を行うには前提として、接続元のクライアントが接続先の公開鍵を持っている必要がある。fingerprintは接続元のクライアントが接続先の公開鍵を持っていない場合に送られてくるものだ。「お前、このfingerprintのやつと接続しようとしてるけど問題ないか?」と聞かれている。一応、公開鍵そのままより人間が確認しやすいからという意味でハッシュ化しているらしいが、こんな英数字の羅列を見て「むむむ..??」となるのは変態くらいだ。

よって、この確認は煩わしいからといってStrictHostKeyCheckingをnoにしたがる輩がいる。そして、あろうことかこんな設定を.ssh/configに書き出すのだ。

host *
        StrictHostKeyChecking no

たとえ深く理解していなくてもこの設定を見たら何となくヤバい匂いを感じることができると思う。 確かに確認が出るのは煩わしい。しかし、確認を出すのは最初の一回きりなのだ。 さて、ここで確認の際にyes/noを入力するとそれぞれどうなるかを見ておく。

  • yesを選択した場合: .ssh/known_hostsに接続先ホストのホスト名、公開鍵を記入し、接続する。
  • noを選択した場合: 接続しない。

先ほど公開鍵認証方式では、接続先の公開鍵を入手していることが前提だと述べた。yesを押すと、.ssh/known_hostsに対象のホストとその公開鍵が保存される。つまり、次回またssh接続する時にはこのknown_hostsの公開鍵を認証に使用することができるのだ。つまり、確認されるのは最初の一回きりなのだ。そのくらいの労は厭わなくても良いのではないだろうか。

ちなみに、StrictHostKeyChecking noを設定するとどうなるか。確認せずに勝手にknown_hostsに接続先のホストと公開鍵が登録される。 ...便利じゃね?どうせfingerprintなんてよく見ずにyes押してるんだから、自動でやってくれるなら好都合だ。

では、まずい例を紹介する。

公開鍵が変わった場合

ちょっとした実験をしてみる。例えば、ssh接続できるサーバーがあったとして、.ssh/known_hostsのそのサーバの公開鍵から最後の一文字だけを取り除いてみる。このままssh接続をしようとすると、デフォルトの設定のままの場合、警告が出る。サーバから取得した公開鍵とクライアントのknown_hostsにある公開鍵が違うからだ。 しかし、例の設定をすると、警告が出ずに新たに.ssh/known_hostsにその公開鍵が追加されるのみだ。今回は実験的に手元のknown_hostsを変えた飲みだが、これは接続先のホストの公開鍵が変わっている場合でも同様だ。 公開鍵が変わっている、つまり接続先のホストが自分が本当に接続したいホストなのかどうかも分からない。さらには中間者攻撃とかをされても気付くことができないということだ。せっかくセキュアにssh接続しようというのにこんな設定を入れてしまっては元も子もない。

ということで

やめようね!

(CIとかテスト環境で仕方なく設定することはあるかもしれないが、それにしても Host * は避けられるしやめた方が良いと思う)