SSHの基礎を押さえる

SSHとは

Secure Shell。

暗号や認証の技術を利用してリモートサーバーと安全に通信を行うためのプロトコル

SSHはクライアントとサーバー間の通信を暗号化する。そのため、安全にリモートサーバーにログインしたり、リモートサーバー上でコマンドを実行できるようになる。

SSHを利用した通信をするには専用のソフトが必要となる。現在はOpenSSHがよく利用されている。

もう少し詳しく

クライアントがリモートサーバーと安全に通信を行うには、

  1. 接続しようとしているサーバーが本当に目的のサーバーなのか?(ホスト認証)
  2. サーバーに接続しようとしているクライアント(ユーザー)は正しいユーザーなのか?(ユーザー認証)

ということを検証する。

この認証には公開鍵認証方式が活用されている。

公開鍵認証方式

公開鍵と秘密鍵の2つの鍵を使ってデータの暗号化、復号を行う公開鍵暗号を利用した認証方式。公開鍵で暗号化されたデータは対となる秘密鍵でしか復号できない仕組みになっている。この性質を利用して、クライアント/サーバーが正規のものかどうかを確認する。

例えば、

ユーザー認証で公開鍵認証方式を利用する場合

  1. クライアントは暗号化用の公開鍵と復号用の秘密鍵を生成する
  2. サーバーに公開鍵を登録する
  3. クライアントが接続要求をすると、サーバーは乱数を公開鍵で暗号化してクライアントに渡す
  4. クライアントは渡された乱数を秘密鍵で復号してハッシュ値を求め、サーバーに渡す
  5. サーバーはクライアントが送り返してきたハッシュ値と元のハッシュ値を比較して一致したら認証する

以上の流れでサーバーはユーザーが正しいユーザーかどうかを判断する。

ポイントはパスワードないし秘密鍵等の重要な情報はネットワーク上に流れないという点である。 暗号化されたデータを盗み見られたとしても、元のデータはわからないし、(秘密鍵が漏洩しない限り)秘密鍵無しでは暗号化されたデータは復号がほぼ不可能であるため、安全にデータのやり取りを行うことができる。

ホスト認証

例えば、悪意のある第三者が同一のIPアドレスでサーバを偽装していて、クライアントがそれに気づかずに正しいパスワードを入力してしまった場合、正規のサーバーに不正ログインされる恐れがある。このようななりすましを防止するための仕組み。ホスト認証にも公開鍵認証が利用されている。

  1. クライアントはサーバーのホストキーの公開鍵を受け取る
  2. クライアントはホストキーの公開鍵で乱数を暗号化してサーバーに渡す
  3. サーバーは渡された乱数をホストキーの秘密鍵で復号してハッシュ値を求め、クライアントに渡す
  4. クライアントはサーバーから受け取ったハッシュ値と元のハッシュ値を比較して一致したら認証する

初回アクセス時はクライアントはサーバーのホストキーの公開鍵を保有していないので、サーバーへの接続を続行するかどうかの確認とともに、指紋(fingerprint)を提示する。

$ ssh -p 50010 hoge@xxxxxxxxxx.vs.sakura.ne.jp
The authenticity of host '[xxxxxxxxxx.vs.sakura.ne.jp]:50010 ([xxx.xxx.xx.xx]:50010)' can't be established.
ECDSA key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxx/x/xxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[xxxxxxxxxx.vs.sakura.ne.jp]:50010,[xxx.xxx.xx.xx]:50010' (ECDSA) to the list of known hosts.
Linux xxxxxxxxxx 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64

このfingerprintを接続前に予めサーバー上で確認しておき、上記で提示されたfingerprintと比較して一致しているかどうか判断する。確認方法は以下。

$ ssh-keygen -l
Enter file in which the key is (/home/hoge/.ssh/id_rsa): /etc/ssh/ssh_host_ecdsa_key.pub
256 SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxx/x/xxxxxxxxxxxxxx. root@xxxxxxxxxx (ECDSA)

初回アクセス以外は基本的に接続要求した時点で自動で認証が行われる。 警告が表示される場合はfingerprintが異なるため、接続を中止し、原因を探る必要がある。

ユーザー認証

サーバーに接続要求するクライアントが正しいユーザーであるかを確認する。 ユーザ認証は主に以下の2通りの認証方式がある。

  1. パスワード認証

    UNIXのユーザーアカウントにログインする時のパスワードをクライアントが入力することでそのクライアントが正しいユーザーであることを認証する。この認証方式は(暗号化されているとはいえ)パスワードをサーバーに送るため、リスクが高い。

  2. 公開鍵認証

    先程の例に書いたように、公開鍵認証はパスワードや秘密鍵などの知られたらアカウントにログインされてしまうような情報はネットワークに流れないため、セキュリティを考慮するとこちらの認証方式を設定することが強く推奨される。

インストールと設定方法

今回はローカル(Mac)の端末からさくらのVPS(Debian9(stretch))にSSHで接続する。

DebianにOpenSSHをインストール

$ sudo apt update

$ sudo apt install ssh

sshをインストールすることで、OpenSSHクライアントとOpenSSHサーバーがインストールされる。

OpenSSHの設定

OpenSSHの設定ファイルsshd_configに設定を記述

念の為、バックアップを取っておく

# cp /etc/ssh/sshd_config /etc/ssh/sshd_config.org

rootでのログインを禁止する

SSH接続でrootにログインできてしまうとすべての操作を実行することができてしまい、セキュリティ上問題があるため、rootでのログインを禁止するための設定をする。

設定方法はsshd_configのPermitRootLoginをnoに変更する。

PermitRootLogin no

これでSSH接続した端末でrootへのログインは禁止され、エラーが出力される。

ポート番号を変更する

SSHサーバーではデフォルトで22番ポートを使用するように設定されている。

このポート番号はSSH接続でよく使用されるポート番号で、これを利用してサーバーに対して攻撃を行うボットが存在している。ポート番号を変更することでこの攻撃の(簡単な)対策が行える。

sshd_configに記述されているPort 22の部分を別の番号に書き換える。

0-65535の間で任意の番号を指定する(ウェルノウンポートは避けたほうが良い。)

Port 50010

sshを再起動して設定を反映させる。

設定を記述しただけでは設定内容が反映されていないため、sshの再起動を行う。

$ sudo /etc/init.d/ssh restart

再起動が完了したら、設定が反映される。

クライアント側の設定

キーペアの作成

まだキーペア(公開鍵と秘密鍵)を作成していなければ、新しく生成する。

$ ssh-keygen -t rsa

コマンドを実行すると、パスフレーズの入力が求められる。

パスフレーズ秘密鍵を使用する時のパスワードに相当する。万が一秘密鍵が漏洩した場合でも正しいパスフレーズを入力しなければ秘密鍵は使用できないようになっている。

キーペアの生成が完了すると、~/.ssh/ディレクトリの中に、id_rsa.pub(公開鍵)とid_rsa(秘密鍵)がそれぞれ作成されている。

このうち、公開鍵であるid_rsa.pubをリモートサーバーに登録する。

公開鍵をサーバーに登録(ssh-copy-idコマンドを使う)

ssh-copy-idコマンドを使って公開鍵をリモートサーバーに登録する。

$ ssh-copy-id -i ~/.ssh/id_rsa.pub サーバーのユーザー名@サーバーのホスト名

このコマンドを使うと、サーバ側へのauthrorized_keysの作成やパーミッションの設定などを自動で行ってくれ、非常に便利。

sshを使ってログインをする

設定が終了したら、実際にログインできるか確認する。

$ ssh -p 50010 サーバーのユーザー名@サーバーのホスト名

-pオプションには先程設定したPort番号を指定する。

パスワードログインを禁止する

ログインできたら、今後はSSH接続のみを許可するために、パスワードログインを禁止する設定をする。

sshd_configのPasswordAuthenticationをnoに変更して、SSH接続している端末でのパスワードログインを禁止する。

PasswordAuthentication no

$ sudo /etc/init.d/ssh restartSSHを再起動。

これで、SSH接続ができるようになる。