SSHについて
日時:
第一章 電子署名編
電子署名とは何か
本人確認の仕組み.重要な二点.
- 本人だけが正しい電子署名を作れる.
- 検証鍵(公開鍵)を持つ誰もがその電子署名がその本人によって書かれたかを検証できる.
以下が具体的な定義.
電子署名の具体的な定義
電子署名(デジタル署名,あるいは単に署名)は三つの効率的なアルゴリズム
- 鍵生成アルゴリズムG
- 署名生成アルゴリズムS
- 署名検証アルゴリズムV
からなる組(G,S,V)でしかるべき追加条件(後述)を満たすもののこと. 電子署名で行われる具体的な手続きは以下の三つからなる.
- Gはセキュリティパラメータkを与えられると,二つのデータp,sを生成する.これらp,sを,それぞれ公開鍵(検証鍵)と秘密鍵(署名鍵)と呼ぶことにする.
- Sは公開鍵pと秘密鍵sとメッセージmを入力すると署名σを生成する.
- Vは公開鍵pとメッセージmと署名σを用いて,0または1を出力する.1なら署名が正しいため受理することに相当し,0なら署名が正しくないため拒否することをに相当する.
また,しかるべき追加条件は以下の通り.
- G(k)=(p,s)の上でV(p,m,S(p,s,m))=1で無ければならない.
- 正しい署名ならばちゃんと受理されなければならないということ.
- 確率的に定義している文献もある(そっちの方が多い?)が,根本的なところは多分同じなので適宜読み替える.
- 秘密鍵を持たない第三者が署名を偽造できないこと.厳密な定式化は省略.
補足事項.
- pは公開する.sは署名を生成する送信者のみが知るもので,秘密にしておく.こうすることで,その送信者が署名したということを誰でも検証することができる.
- 電子署名において鍵とは単に署名を作るための情報(S,Vに与えるパラメータ).
第二章 SSH編
- SSHとはプロトコル.
- 基本的な用途の一つにサーバへの遠隔ログインがある.
- 今回の場合は遠隔ログインしなくても直接コンソールの画面からアクセスできたが,スクロールが効かないなど柔軟性に欠けている上に,もっさりしていて普段使いには堪えないため,手元のターミナルエミュレータから遠隔ログインをする手法を選ぶ.
- 現在はOpenSSHと呼ばれるソフトウェアを用いて利用することがかなり多い.
- サーバ上のユーザにログインするために,パスワードで認証する方法(パスワード認証)と,公開鍵を用いて認証する方法(公開鍵認証)がある.公開鍵認証を採用する.
SSHの公開鍵認証の仕組み
- 四つの鍵が主役
- クライアントの公開鍵・秘密鍵(クライアントが作った公開鍵・秘密鍵のこと).
- サーバの公開鍵・秘密鍵(サーバが作った公開鍵・秘密鍵のこと).
- サーバに置いたクライアントの公開鍵ことではない.
- クライアントは公開鍵と秘密鍵のペアを作成する.公開鍵はサーバ側にも置いておくが,秘密鍵はクライアント側だけに置く.秘密鍵は絶対に他の人に見られてはいけない.公開鍵は誰に見られても問題ない(見せる必要もないけど).
- サーバの公開鍵はクライアント側にも置いておく.サーバの秘密鍵はクライアント含めもちろん誰にも知られてはいけない.
- サーバが秘密鍵で作った署名をクライアントがサーバの公開鍵で検証し,接続先のサーバが所望のものか調べる.
- クライアントが手元の秘密鍵を用いて署名を作り,サーバ側があらかじめ置かれた公開鍵で検証することで,ログインを許可する.
- SSHでは毎回変わるセッション識別子を用いて署名を作成しているため,仮に署名が盗聴されたとしても,使いまわせないようになっている.
認証の手順:
- クライアント側が公開鍵と秘密鍵のペアを作成する.
- 公開鍵を何らかの方法でログインしたいサーバ側に登録する.
- クライアントがサーバにアクセスする.
- サーバとクライアントが通信の暗号化で用いる暗号アルゴリズムについて合意し,予測不可能な値(セッション鍵とセッション識別子)を共有しつつ,サーバ認証を行う.サーバ認証ではあらかじめクライアントが入手しておいたサーバの公開鍵を用いて,サーバ側がセッション識別子からサーバ側の秘密鍵で作った署名が正しいかどうか検証する.
- 合意した暗号アルゴリズムとセッション鍵を用いて,共通鍵暗号による通信の暗号化を開始する.以降の通信は,これによって暗号化される.
- クライアントはセッション識別子とクライアント側の秘密鍵を用いて作った署名とクライアントの公開鍵をサーバに送る.
- サーバ側は公開鍵がそのユーザに登録されたものかを確認し,それを用いて検証する.正しい署名であった場合,ログインを許可する.
実際に設定する.
公開鍵認証の設定(クライアント側)
手元のUbuntu22.04 LTSに入っているOpenSSH(サーバとクライアント側の両方の機能を持つ)を用いる.
- 違う環境なら,作った鍵がどこにどう保存されるかは場合によるので適宜読み替える.
-
クライアント側で以下のコマンドで秘密鍵と公開鍵のペアを作成.手元のUbuntuの
~/.ssh
に鍵が出来る.keyname
の部分は分かりやすいものに.秘密鍵と公開鍵がそれぞれkeyname
とkeyname.pub
という名前で作られる.-C "thisiscomment"
のところは,公開鍵の最後につく文字列を指定しているだけ.認証には関係ない.いらなかったら-C ""
で置き換える.
$ ssh-keygen -t ed25519 -P "" -f ~/.ssh/keyname -C "thisiscomment"
- 注釈
-t
で鍵の種類の指定.公開鍵認証に使える鍵にもいろいろ種類があり,それを指定する.- 今回はed25519を使う.何にも指定しないとRSAで作られる.
- RSAとed25519のどちらがいいかは,ちゃんと理解はしていないがed25519が推奨されている記述が多い印象.
- 例えばGithubの公式ドキュメントではed25519での手順が本筋として記載されている(参考:https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent).
-P
でパスフレーズ指定.入力すると秘密鍵を使うたびに,そのパスフレーズを求められる.設定しておけば秘密鍵を万が一盗まれてもパスフレーズがわからなければ読み取られないため,時間稼ぎができる.ただし,盗んだ側は何回もパスワードを当てるべく試行錯誤できるため,設定する場合は十分すぎる強度のものにする.今回は何も入れてないが,出来れば入れる.生成した後に改めて設定することもできる.-f
でファイル指定.これがないと鍵の種類に応じてid_ed25519
やid_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-----
-
以下のコマンドを実行し,秘密鍵
~/.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
次にサーバ側の設定に移る.
公開鍵認証の設定(サーバ側)
-
サーバのコンソールを開いて先ほど作った一般ユーザでログインする.
-
~/.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にしている. - OpneSSHでは公開鍵はログインしたいユーザ(今の一般ユーザ)のホームディレクトリ以下にある
-
一旦,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制限すると不特定の出先でアクセス出来なくなるデメリット?はある).今回はこの最低限の設定で.
- rootユーザのログインを禁止.
-
configの構文がおかしくないか以下を実行して検証.問題なければ何も出ない.問題があればエラーが出る.
# sshd -t
-
問題なければ設定を反映するためにsshdを再起動.
# systemctl restart sshd
-
初回ログイン時に確認に必要な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ユーザのまま設定を続ける.
- ファイアウォールとは
- サーバを攻撃から守る仕組みの一つ
- 特定のIPアドレスからの通信や,ポート番号への通信を拒否できる.
- ポート番号とはネットワークに繋がった一つ機器で動いている複数のアプリケーションを識別するために用いられる番号のこと.IPアドレスだけでは一つの機器の中でどのアプリケーションにデータを届ければいいのか分からない.それをポート番号によって識別する.
- 今回は簡単に扱えるufwを用いるが,nftablesが使いこなせるならそっちの方がいい.
(もちろん)サーバ側で操作する.
-
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
- sshで使うポート番号への通信を「30秒に6回まで」という制限付きで許可する.
-
次に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
-
ConohaのコントロールパネルでIPv4とIPv6の接続許可ポートを「全て許可」に設定.これはまた別のファイアウォールのようなので,行わないと次のSSHを使った遠隔ログインが出来ない.
実際にSSHでログインする.
-
すでに,クライアント側で以下のコマンドを実行すればログインできるはず(が今回はこれを実行しない.仮にした場合は下の4番へ).ただし,設定内容に応じて以下のようにする.
keyname
は鍵生成時に指定したものに置換.user12345
は実際に作ったユーザ名に置換.50022
は設定したポート番号に置換.192.0.2.59
はサーバのIPアドレス.
$ ssh -i ~/.ssh/keyname -l user12345 -p 50022 192.0.2.59
しかし,毎回これを打つのは面倒であり間違えるおそれがあるため,通常はクライアント側の設定ファイル
~/.ssh/config
を編集して行う. -
そこで,クライアント側で
$ 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 ......
-
以下のコマンドを実行.
MyServer
は上の設定ファイルのHost
の横に記した文字列で.$ ssh MyServer
-
サーバ認証のために以下のような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
に追加される.次回からはこの保存したサーバの公開鍵でサーバ認証すればいいため,この手続きは省略される.
- 初回でfingerprintの確認をしたら,このサーバのIPアドレスまたはドメイン名(をハッシュ化したもの)とサーバ認証のための公開鍵のペアがクライアント側のファイル
-
ログイン成功!
参考文献
- Ylonen, T. and C. Lonvick, Ed., “The Secure Shell (SSH) Authentication Protocol”, RFC 4252, 2006, https://www.rfc-editor.org/info/rfc4252
- Ylonen, T. and C. Lonvick, Ed., “The Secure Shell (SSH) Transport Layer Protocol”, RFC 4253, 2006, https://www.rfc-editor.org/info/rfc4253
- OpenSSH: Manual Pages, https://www.openssh.com/manual.html
- 光成滋生, 『図解即戦力 暗号と認証のしくみと理論がこれ一冊でしっかりわかる教科書』, 技術評論社, 2021
- IPUSIRON, 『暗号技術のすべて』, 翔泳社, 2017
- 「電子署名=『秘密鍵で暗号化』」という良くある誤解の話, https://qiita.com/angel_p_57/items/d7ffb9ec13b4dde3357d
- SSHの公開鍵認証における良くある誤解の話, https://qiita.com/angel_p_57/items/2e3f3f8661de32a0d432
- あなたの「公開鍵暗号」はPKE? それともPKC?, https://blog.cybozu.io/entry/2021/12/28/080000
- 電子署名の基礎知識, https://qiita.com/angel_p_57/items/437ca6235defc938b97d
- 2つの公開鍵暗号(公開鍵暗号の基礎知識), https://qiita.com/angel_p_57/items/897bf94160be8d637585
- 電子署名による認証(身分証明), https://qiita.com/angel_p_57/items/a8ed4e00cb04ebcccb98
- 平成29年度 秋期 基本情報技術者過去問題 午後 問1, https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2017h29.html