SSHのプロトコルについてまとめてみた 第一弾

## はじめに
* こんにちは。[CYBIRDエンジニア Advent Calender](http://qiita.com/advent-calendar/2016/cybird) 22日目を担当する[@Nate-River56](http://qiita.com/Nate-River56)です。
    * 新卒1年目, 今年度入社のエンジニアです。
    * 12日目, [ガトリング砲をぶっ放した話](http://qiita.com/Nate-River56/items/394a38d26e94565db31a)もぜひみてください！
* 昨日, 21日目は[@gotyoooo](http://qiita.com/gotyoooo)さんの[B+Treeインデックスに関してよく出る言葉の正誤とその解説
](http://gotyoooo.hatenablog.com/entry/2016/12/21/000301)でした。
  * 会社の左隣にいらっしゃる方の記事です。
    * マッシュアップエンジニアを体現したすごいエンジニアの方です。
  * RDBMSの中身の仕組みについて詳しくない自分のための記事ですね。。

## SSHについて
* 皆さん, SSH使っていますか？ ほとんどすべてのエンジニアがSSHを使用していると思います。
* インフラエンジニアでなくても, デプロイや設定, gitでSSHを使用しているので, SSHを使わなければいけないシーンがあるのではないでしょうか。
* 日常的に使っているSSHとはそもそもなんなのか, どのように盗聴されていない・改ざんされていないことを担保するのかについて再度学習してみました。
* 今回はSSHのプロトコルについて, 実際に接続した際の流れをまとめてみました。
* 今回はパスワード認証ではなく, 公開鍵暗号化方式を使用したSSHということですすめていきたいと思います。

## SSH Protocol2における接続時のシーケンス図
* TeraTermのマニュアルページに参考になるシーケンス図がございましたので, こちら使用させていただいております。

![TeraTerm Reference Figure1](http://ttssh2.osdn.jp/manual/ja/reference/image/ssh2_sequence1.png)

段階を追って説明していきます！

## SSHでリモートに接続した際の流れ

### 1. バージョンの相互確認
* 相互のバージョンに応じて, アルゴリズムを利用するようにする。
    * 相手のバージョンについては, 以下のようにnetcatやtelnetで確認する事ができます。

```bash
$ telnet hogehoge.com 22

# サーバーの対応するバージョンを返してくる
SSH-2.0-OpenSSH_6.6.1p1-RHEL7-6.6.1p1-25 

# クライアントのバージョンを入力する
SSH-2.0-OpenSSH_7.4 

# サーバーがアルゴリズムを提案してくる
ތfurve25519-sha256@libssh.org,ecdh-sha2-nistp256,.... 
```

* `ssh -v`で確認するところの次の出力に当たります。

```bash
# protocol2を選択する
debug1: Enabling compatibility mode for protocol 2.0 

# ローカルのOpenSSHバージョン
debug1: Local version string SSH-2.0-OpenSSH_7.4 

# リモートのOpenSSHバージョン
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.6.1p1-RHEL7-6.6.1p1-25

# 以下のバージョンのプロトコルでやる
debug1: match: OpenSSH_6.6.1p1-RHEL7-6.6.1p1-25 pat OpenSSH_6.6.1* compat 0x04000000
```

### 2. 共通鍵の交換
* Diffie-Hellman鍵交換法で共通鍵暗号化方式の共通鍵を交換する。
    * 公開鍵暗号化方式では, 暗号化に時間がかかり一方向の暗号化しか行うことが出来ないため公開鍵暗号化方式で共通鍵の受け渡しを行う。

```bash
debug1: Authenticating to hogehoge.com:22 as 'remote-hoge'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received

# 鍵交換のアルゴリズムを決定する
debug1: kex: algorithm: curve25519-sha256@libssh.org
debug1: kex: host key algorithm: ecdsa-sha2-nistp256

# サーバーから共通鍵としてAES 256bit CTRモードを提案
# メッセージ認証符号(MAC)の方式を決定;改ざん検知に使用する
debug1: kex: server->client cipher: aes256-ctr MAC: umac-64-etm@openssh.com compression: zlib@openssh.com

# クライアントから共通鍵としてAES 256bit CTRモードを提案
debug1: kex: client->server cipher: aes256-ctr MAC: umac-64-etm@openssh.com compression: zlib@openssh.com
```

### 3. リモートホストの確認
* リモートホストが悪意を持ったサーバーになりすましを受けていないかを確認する。
    * 相手のサーバーが保有しているのは公開鍵なので, 漏れた公開鍵を利用しなりすましを受ける可能性はある。
    * ローカルのknown_hostsに初回接続時にFingerprintを残し, 毎回の接続時にFingerprintを照合する。
* もし, 自分の操作でマシンを切り替えて, かつIPアドレスに変化のない場合は該当するFingerprintを削除し再度登録することで警告を出さなくなる。

```bash
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ecdsa-sha2-nistp256 SHA256:l1AGSlrOJX/k1Uu7ih4VscJkbzckOSwHtS8Pu0O50mU

# known_hostsと/etc/ssh/ssh_host_rsa_key.pubの照合
debug1: Host '[hogehoge.com]:22' is known and matches the ECDSA host key.
debug1: Found key in /Users/local-hoge/.ssh/known_hosts:10
```

* Finderprintは`/etc/ssh/ssh_host_rsa_key.pub`に存在し, OpenSSHのインストール時に作成しているようです。
    * これで持って, ホストを識別しています。
    * 例えば, AMIやrsync等でまるっと中身をコピーしたサーバーを複数台立てると`/etc/ssh/ssh_host_rsa_key.pub`がコピーされるのでFinderprintが同じホストが複数できることになります。
    * またIPアドレスや, IPアドレスから逆引きした際に得られたホスト名も合わせて照合しているようです。 

## まとめ
* 調べてみると, ものすごい奥が深くすべて調べきりませんでした...
    * `known_hosts`はどのように生成されているのか。
        * ホスト固有の情報を使っているのか。
    * 暗号利用モードとは？
    * パスワード認証ではどのようにパスワードがやりとりされているのか。
        * ハッシュ化されたパスワードをサーバー側で照合しているのか。
* デファクトなSSH実装であるOpenSSHがつい最近リリースされたバージョン(7.4)では, SSH Protocol 1のサーバーサポートを打ち切ったようです。<https://mag.osdn.jp/16/12/20/160000>
* サーバーもしくはクライアントのバージョンが古いと, 強度の弱いarcfourやMD5が使用されることがあるので脆弱性のある暗号化方式・ハッシュを選択しないように設定・アップデートを行う必要がある。
    * たしかに共通鍵暗号化方式はaesよりarcfourの方が`scp`や`sftp`でファイルを転送したときに早いので, インターネットに通信が出ないSSHであればarcfourを選択するのもありだと思います。
* 私自身も含めてセキュリティに関して興味を持つきっかけになればなと思います。

## 次回について
* いったん, ここまでとさせていただきます。~~間に合わなかった。~~
* 続きの第二弾をご期待下さい！ 
    * [実用SSH](https://www.oreilly.co.jp/books/4873112877/)を読んでおかないとまずいです...

## Disclaimer
* 今回のこの記事は私自信の勉強も兼ねさせております。
    * そのため正確性に関しては保証いたしかねます。参考程度にしていただけると幸いです。
* もし正しくない点等ございましたら, 以下コメント欄からご指摘いただけると大変ありがたいです。

## 最後に
* さて, 明日は会社で右隣に座ってらっしゃる[@kenchang100kg](kenchang100kg kenchang100kg)さんの[Zabbix 3.0 でログのデータからグラフを作る]()です。非常に楽しみです。
    * 21日目・22日目・23日目のAdvent-Calender, 偶然席順と同じになってますね笑

## 参考URL
<http://ttssh2.osdn.jp/manual/ja/reference/sourcecode.html#ttssh>
<http://bie.inf.kyushu-u.ac.jp/~yosinori/ssh/protocol-j.html>
<http://www.unixuser.org/~euske/doc/openssh/book/chap3.html>