SSHについて

日時:

昔作った記事.SSHについて簡単にまとめたもの.

第一章 電子署名編

電子署名とは何か

本人確認の仕組み.重要な二点.

以下が具体的な定義.

電子署名の具体的な定義

電子署名(デジタル署名,あるいは単に署名)は三つの効率的なアルゴリズム

からなる組(G,S,V)でしかるべき追加条件(後述)を満たすもののこと. 電子署名で行われる具体的な手続きは以下の三つからなる.

  1. Gはセキュリティパラメータkを与えられると,二つのデータp,sを生成する.これらp,sを,それぞれ公開鍵(検証鍵)と秘密鍵(署名鍵)と呼ぶことにする.
  2. Sは公開鍵pと秘密鍵sとメッセージmを入力すると署名σを生成する.
  3. Vは公開鍵pとメッセージmと署名σを用いて,0または1を出力する.1なら署名が正しいため受理することに相当し,0なら署名が正しくないため拒否することをに相当する.

また,しかるべき追加条件は以下の通り.

補足事項.

第二章 SSH編

手順書として読む場合,この章は「公開鍵認証の設定(クライアント側)」の手前まで飛ばす.

SSHの公開鍵認証の仕組み

認証の手順:

  1. クライアント側が公開鍵と秘密鍵のペアを作成する.
  2. 公開鍵を何らかの方法でログインしたいサーバ側に登録する.
  3. クライアントがサーバにアクセスする.
  4. サーバとクライアントが通信の暗号化で用いる暗号アルゴリズムについて合意し,予測不可能な値(セッション鍵とセッション識別子)を共有しつつ,サーバ認証を行う.サーバ認証ではあらかじめクライアントが入手しておいたサーバの公開鍵を用いて,サーバ側がセッション識別子からサーバ側の秘密鍵で作った署名が正しいかどうか検証する.
  5. 合意した暗号アルゴリズムとセッション鍵を用いて,共通鍵暗号による通信の暗号化を開始する.以降の通信は,これによって暗号化される.
  6. クライアントはセッション識別子とクライアント側の秘密鍵を用いて作った署名とクライアントの公開鍵をサーバに送る.
  7. サーバ側は公開鍵がそのユーザに登録されたものかを確認し,それを用いて検証する.正しい署名であった場合,ログインを許可する.

実際に設定する.

公開鍵認証の設定(クライアント側)

VPSを建てた際に入手した秘密鍵がすでにあるが,改めて一からやる.

手元のPCのWSL2(Ubuntu22.04 LTS)に入っているOpenSSH(サーバとクライアント側の両方の機能を持つ)を用いる.

  1. クライアント側で以下のコマンドで秘密鍵と公開鍵のペアを作成.手元のUbuntuの~/.sshに鍵が出来る.

    • keynameの部分は分かりやすいものに.秘密鍵と公開鍵がそれぞれkeynamekeyname.pubという名前で作られる.
    • -C "thisiscomment"のところは,公開鍵の最後につく文字列を指定しているだけ.認証には関係ない.いらなかったら-C ""で置き換える.
     $ ssh-keygen -t ed25519 -P "" -f ~/.ssh/keyname -C "thisiscomment"
    
    • 注釈
      • -tで鍵の種類の指定.公開鍵認証に使える鍵にもいろいろ種類があり,それを指定する.
      • -Pでパスフレーズ指定.入力すると秘密鍵を使うたびに,そのパスフレーズを求められる.設定しておけば秘密鍵を万が一盗まれてもパスフレーズがわからなければ読み取られないため,時間稼ぎができる.ただし,盗んだ側は何回もパスワードを当てるべく試行錯誤できるため,設定する場合は十分すぎる強度のものにする.今回は何も入れてないが,出来れば入れる.生成した後に改めて設定することもできる.
      • -fでファイル指定.これがないと鍵の種類に応じてid_ed25519id_rsaというデフォルトの名前で作られる.何のためのものかが分かりづらいし,ファイル名は指定する.
      • RSAで作った場合はビット長を指定するオプションが追加であるが,今回はRSAで作らないので説明省略.

    生成した公開鍵は以下のコマンドで見ることができます.出力結果を見ると分かるようにOpenSSHでは公開鍵は(やや長い)一行.

     $ cat ~/.ssh/keyname.pub
     ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI<以降複雑な長い文字列> thisiscomment
    
    • -C ""で作ったら最後のthisiscomentの部分はない.-C自体指定しないで作った場合はuser@hostnameみたいな形式になる.

    秘密鍵も以下の様に実行すれば見ることができる(他人には見せない!).

    • *の部分は複雑な文字列
     $ cat ~/.ssh/keyname
     -----BEGIN OPENSSH PRIVATE KEY-----
     **********************************************************************
     **********************************************************************
     **********************************************************************
     **********************************************************************
     ****************************************************************
     -----END OPENSSH PRIVATE KEY-----
    
  2. 以下のコマンドを実行し,秘密鍵~/.ssh/keynameのパーミッションを600(所有者のみ読み書き出来る)に変える(こうでないと接続時にエラーが出る,が,最初から600になっているとは思う,が,念のため).

     $ chmod 600 ~/.ssh/keyname
    

    以下のように秘密鍵のあるファイルの一覧を見て,秘密鍵のファイルのパーミッションが下の様に -rw-------になっていたらよし.

    • keynameは設定したファイル名.client_userはOpenSSHをクライアント側で使うユーザ(サーバのものとは関係なし).
     $ ls -l ~/.ssh
     -rw------- 1 client_user client_user  411 Nov 30 23:48 keyname
    

    次にサーバ側の設定に移る.

公開鍵認証の設定(サーバ側)

  1. サーバのコンソールを開いて先ほど作った一般ユーザでログインする.

  2. ~/.ssh/authorized_keysに公開鍵を追記して保存する.

    • OpneSSHでは公開鍵はログインしたいユーザ(今の一般ユーザ)のホームディレクトリ以下にあるauthorized_keysに登録するのがデフォルトの設定.~はそのユーザのホームディレクトリで,デフォルトでは/home/ユーザ名になる.

    例えばコンソールからで

     $ mkdir ~/.ssh
     $ chmod 700 ~/.ssh
     $ touch ~/.ssh/authorized_keys
     $ chmod 600 ~/.ssh/authorized_keys
     $ vi ~/.ssh/authorized_keys
    

    と入力し,挿入モードでコンソール上にある「テキスト送信」から公開鍵をコピペし,保存する.パーミッションは~/.sshを700に~/.ssh/authorized_keysを600にしている.

  3. 一旦,rootユーザになる.以下のコマンドでrootユーザのパスワードを求められるので入力する.

     $ su -
    

    ファイル/etc/ssh/sshd_config

     # vi /etc/ssh/sshd_config
    

    で以下のように編集する.

    設定内容

    • rootユーザのログインを禁止.
      • 絶対に存在するユーザであり,外部からの無差別なログイン試行の対象になるから.
    • パスワード認証を禁止.
    • ポート番号を22から別のものに変更.他のアプリケーションと被ってはいけない
      • 1024~65535の範囲で設定すればいいと書いてある記事が多かった.別のアプリケーションによって使われてなければ大丈夫だろうが,一番無難なのは49513~65535の範囲かもしれない.
      • 1023以下は他のアプリケーションが使う可能性が高いため避ける.
     # #で該当箇所をコメントアウトし,その下に改めて設定を書いた.
     # 直接変更してもいいと思う.
     # 場合によっては最初から該当箇所がコメントアウトされているかもしれないが,いずれにせよ下のコメントアウトされてない三つは明記する.
     
     # PermitRootLogin yes
     PermitRootLogin no
     
     # PasswordAuthentication yes
     PasswordAuthentication no
     
     # Port 22
     # 50022は例
     Port 50022
    

    他にもログイン可能なIPを制限することなど,追加で色々やりようはあるが,詳しくは略(IP制限すると不特定の出先でアクセス出来なくなるデメリット?はある).今回はこの最低限の設定で.

  4. configの構文がおかしくないか以下を実行して検証.問題なければ何も出ない.問題があればエラーが出る.

     # sshd -t
    
  5. 問題なければ設定を反映するためにsshdを再起動.

     # systemctl restart sshd
    
  6. 初回ログイン時に確認に必要なfingerprintをメモする.以下を実行.

     # ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub
     256 SHA256:<複雑な文字列> root@hogehoge (ED25519)
    

    これで表示された<複雑な文字列>を何らかの手段で覚えておく.初回ログイン時のホスト確認用に使う.

    • これはサーバ側の公開鍵ssh_host_ed25519_key.pubのハッシュ値した値が表示される.
    • 今回のようにsshで何かしらのサーバにアクセスする際には,このfingerprintの確認手順をする.この手順を怠ると初回接続時に中間者攻撃を受けるおそれがある.

ファイアウォールとfail2banの設定

rootユーザのまま設定を続ける.

(もちろん)サーバ側で操作する.

  1. ufwのデフォルトのincomingをdenyにし,以下の設定をして有効にし,状態を確認する.

    • sshで使うポート番号への通信を「30秒に6回まで」という制限付きで許可する.50022は先ほど設定したポート番号に.
     # ufw default deny
     # ufw limit 50022/tcp
     # ufw enable
     # ufw status verbose
     Status: active
     Logging: on (low)
     Default: deny (incoming), allow (outgoing), disabled (routed)
     New profiles: skip
    
     To                         Action      From
     --                         ------      ----
     50022                      LIMIT IN    Anywhere
     50022 (v6)                 LIMIT IN    Anywhere (v6)
    

    もし,デフォルトのOpenSSHに関する設定が残っていたら消す.消し方は

     # ufw delete allow OpenSSH
    

    かstatusを番号付きで表示して該当番号をnとしufw delete nで消すかのどちらかで.番号は削除するたびに変わるので注意.

     # ufw status numbered
     # ufw delete 1
    
  2. 次にfail2banを設定し,機能させる.

    • fail2banはログファイルをスキャンして,設定内容に応じて不届き者等のIPアドレスをBANしてくれるもの.今回は,ログイン認証を何回も短時間にしまくる不届き者をBANする設定を書く.
     # apt install fail2ban
    

    でfail2banをインストールしたら(すでにされているかもしれない)

     # vi /etc/fail2ban/jail.local 
    

    で以下のような内容を書く.50022はさっき設定したSSH用のポート番号に置換.

    • 下のは一例.600秒の間で5回リトライしてSSHでのログイン試行が失敗したIPアドレスのポート番号50022へのアクセスを86400秒(=1日)禁止する.
     [sshd]
     enabled = true
     port = 50022 
     bantime  = 86400
     findtime  = 600
     maxretry = 5
    

    以下のコマンドで動かす.

     # systemctl restart fail2ban
    
  3. ConohaのコントロールパネルでIPv4とIPv6の接続許可ポートを「全て許可」に設定.これはまた別のファイアウォールのようなので,行わないと次のSSHを使った遠隔ログインが出来ない.

実際にSSHでログインする.

  1. すでに,クライアント側で以下のコマンドを実行すればログインできるはず(が今回はこれを実行しない.仮にした場合は下の4番へ).ただし,設定内容に応じて以下のようにする.

    • keynameは鍵生成時に指定したものに置換.
    • user12345は実際に作ったユーザ名に置換.
    • 50022は設定したポート番号に置換.
    • 192.0.2.59はサーバのIPアドレス.
     $ ssh -i  ~/.ssh/keyname -l user12345 -p 50022 192.0.2.59
    

    しかし,毎回これを打つのは面倒であり間違えるおそれがあるため,通常はクライアント側の設定ファイル~/.ssh/configを編集して行う.

  2. そこで,クライアント側で

     $ vi ~/.ssh/config
    

    とし以下のように書き込む.

     # ~/.ssh/configの一例.必要な範囲だけ.
     # Hostが一つの設定の区切りの標識.
     # MyServerは好きな文字列で(自分が識別しやすいものがいい).
     Host MyServer
         # サーバのIPアドレス.192.0.2.59をサーバのIPアドレスに置き換える.
         Hostname 192.0.2.59
         # ログインしたいユーザをUser以下に.user12345はその名前に置き換える.
         User user12345
         # 設定したポート番号,変更したはずなのでその値に50022を置き換える.
         Port 50022
         # クライアント側の秘密鍵の位置.keynameは秘密鍵の名前に置き換える.
         IdentityFile ~/.ssh/keyname
     
     # 今回はいらないが,今後,他のサーバの設定も書きたくなったら同様に続けて書けばいい  
     # 以下は今回は書かなくていい.
    
     Host MySecondServer
         Hostname 192.0.2.60
         User user123456
         Port 50023
         IdentityFile ~/.ssh/keyname_second
    
     Host MyThirdServer
          ......
    
  3. 以下のコマンドを実行.MyServerは上の設定ファイルのHostの横に記した文字列で.

     $ ssh MyServer
    
  4. サーバ認証のために以下のようなfingerprintの確認画面が出るはず.

     The authenticity of host '192.0.2.59 (192.0.2.59)' can't be established.
     ED25519 key fingerprint is SHA256:<乱雑な文字列>.
     Are you sure you want to continue connecting (yes/no)?
    

    SHA256:<複雑な文字列>とメモしていたものとを比較し,同じだった場合はyesを入力.違う場合(基本的に起こらないと思うが)ならnoにして,個別に原因を探る.

    • 初回でfingerprintの確認をしたら,このサーバのIPアドレスまたはドメイン名(をハッシュ化したもの)とサーバ認証のための公開鍵のペアがクライアント側のファイル~/.ssh/known_hostsに追加される.次回からはこの保存したサーバの公開鍵でサーバ認証すればいいため,この手続きは省略される.
  5. ログイン成功!今後は基本的にSSHの遠隔ログインを用いて操作すればよく,常時コンソールを使う必要はない.

参考文献

  1. Ylonen, T. and C. Lonvick, Ed., “The Secure Shell (SSH) Authentication Protocol”, RFC 4252, 2006, https://www.rfc-editor.org/info/rfc4252
  2. Ylonen, T. and C. Lonvick, Ed., “The Secure Shell (SSH) Transport Layer Protocol”, RFC 4253, 2006, https://www.rfc-editor.org/info/rfc4253
  3. 光成滋生, 『図解即戦力 暗号と認証のしくみと理論がこれ一冊でしっかりわかる教科書』, 技術評論社, 2021
  4. IPUSIRON, 『暗号技術のすべて』, 翔泳社, 2017
  5. 「電子署名=『秘密鍵で暗号化』」という良くある誤解の話, https://qiita.com/angel_p_57/items/d7ffb9ec13b4dde3357d
  6. SSHの公開鍵認証における良くある誤解の話, https://qiita.com/angel_p_57/items/2e3f3f8661de32a0d432
  7. あなたの「公開鍵暗号」はPKE? それともPKC?, https://blog.cybozu.io/entry/2021/12/28/080000
  8. 電子署名の基礎知識, https://qiita.com/angel_p_57/items/437ca6235defc938b97d
  9. 2つの公開鍵暗号(公開鍵暗号の基礎知識), https://qiita.com/angel_p_57/items/897bf94160be8d637585
  10. 電子署名による認証(身分証明), https://qiita.com/angel_p_57/items/a8ed4e00cb04ebcccb98
  11. 平成29年度 秋期 基本情報技術者過去問題 午後 問1, https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2017h29.html