第4章: 暗号通信理論とSSHプロトコル - セキュアリモートアクセスの計算機科学的基盤
4.1 リモートアクセスの歴史と課題
タイムシェアリングからネットワークへ
1960年代のタイムシェアリングシステムでは、ユーザーは物理的に接続された端末からシステムにアクセスしていました。端末とメインフレームは同じ建物内にあり、通信の傍受は物理的なアクセスを必要としました。
1969年、ARPANETの誕生により状況が一変しました。遠隔地のコンピュータにネットワーク経由でアクセスできるようになりましたが、これは新たなセキュリティ課題をもたらしました。
> "ネットワークを介した通信は、その経路上のすべての地点で傍受される可能性がある。" — Saltzer & Schroeder, 1975
Telnetの問題
1969年に開発されたTelnetは、最初の標準的なリモートアクセスプロトコルでした。RFC 15として文書化されたTelnetは、シンプルで実装が容易でしたが、致命的な欠陥がありました:
クライアント サーバー
│ │
│───── ユーザー名: alice ─────────────→│
│ │
│───── パスワード: secret123 ─────────→│
│ │
│←──── ログイン成功 ───────────────────│
│ │
↑
すべて平文で送信
ネットワーク上の誰でも傍受可能
1980年代、インターネットの商用利用が始まると、Telnetのセキュリティ問題は深刻化しました。パケットスニッフィングにより、パスワードが容易に盗聴されるようになりました。
Berkeley r-commands
1982年、UCバークレーはrlogin, rsh, rcpなどの「r-commands」を開発しました。これらは.rhostsファイルによるホストベース認証を提供しましたが、以下の問題がありました:
- IPスプーフィングに脆弱
- ホスト信頼モデルの欠陥
- 暗号化なし
1988年のMorris Wormは、これらのプロトコルの脆弱性を悪用し、インターネット全体に感染しました。セキュアなリモートアクセスの必要性が明確になりました。
4.2 公開鍵暗号の理論的基盤
暗号学の二つのパラダイム
暗号学は、情報を安全に送信するための数学的技術です。歴史的に2つのアプローチがあります:
対称鍵暗号(Symmetric Key Cryptography)
同じ鍵で暗号化と復号を行います:
平文 ──[鍵K]──→ 暗号文 ──[鍵K]──→ 平文
暗号化 復号
例: AES(Advanced Encryption Standard)
問題: 鍵をどうやって安全に共有するか?(鍵配送問題)
非対称鍵暗号(Asymmetric Key Cryptography)
公開鍵と秘密鍵のペアを使用します:
平文 ──[公開鍵]──→ 暗号文 ──[秘密鍵]──→ 平文
暗号化 復号
公開鍵: 誰でも知ってよい(公開可能)
秘密鍵: 所有者だけが持つ(絶対に秘密)
Diffie-Hellman鍵交換
1976年、Whitfield DiffieとMartin Hellmanは、論文"New Directions in Cryptography"で革命的なアイデアを発表しました。
鍵交換問題: 盗聴者が存在するネットワーク上で、二者間で共有秘密を確立できるか?
解決策(離散対数問題に基づく):
1. AliceとBobは公開パラメータ(素数p、生成元g)に合意
2. Alice: 秘密の数 a を選び、A = g^a mod p を計算
Bob: 秘密の数 b を選び、B = g^b mod p を計算
3. AliceはAをBobに送信(盗聴されても安全)
BobはBをAliceに送信(盗聴されても安全)
4. Alice: s = B^a mod p = (g^b)^a mod p = g^(ab) mod p
Bob: s = A^b mod p = (g^a)^b mod p = g^(ab) mod p
5. AliceとBobは同じ値 s を共有している!
攻撃者はAとBを知っていても、sを計算できない
(離散対数問題の計算困難性による)
この発見はチューリング賞に値する画期的な業績でした。
RSA暗号
1977年、MITのRon Rivest、Adi Shamir、Leonard AdlemanはRSA暗号を発明しました。これは公開鍵暗号と電子署名を実現する最初の実用的なアルゴリズムです。
RSAの数学的基盤:
鍵生成:
1. 大きな素数 p, q を選択
2. n = p × q を計算
3. φ(n) = (p-1)(q-1) を計算
4. φ(n)と互いに素な e を選択
5. d ≡ e^(-1) (mod φ(n)) を計算
公開鍵: (n, e)
秘密鍵: (n, d)
暗号化: c = m^e mod n
復号: m = c^d mod n
安全性: n を素因数分解することは計算上困難
(2048ビットのnを分解するには数十億年かかる)
電子署名
公開鍵暗号は電子署名も可能にします:
署名生成(秘密鍵で):
メッセージm のハッシュを計算: h = Hash(m)
署名: σ = h^d mod n
署名検証(公開鍵で):
h' = σ^e mod n
h'' = Hash(m)
h' == h'' なら署名は有効
電子署名は以下を保証します:
- 認証: 署名者の身元を確認
- 完全性: メッセージが改ざんされていない
- 否認防止: 署名者は後から否定できない
現代の公開鍵アルゴリズム
RSA(1977)
- 最も広く使用されている
- 2048ビット以上が推奨
- 計算コストが高い
楕円曲線暗号(ECC, 1985)
- Neal Koblitz と Victor Miller が独立に発明
- RSAより短い鍵で同等のセキュリティ
- Ed25519: 現代のSSHで推奨
セキュリティ等価性:
RSA 2048ビット ≈ ECC 224ビット
RSA 3072ビット ≈ ECC 256ビット
Ed25519: 128ビットセキュリティ、256ビット鍵
4.3 SSHプロトコルの設計と歴史
SSHの誕生
1995年、フィンランドのTatu Ylönenは、ヘルシンキ工科大学でパスワードスニッフィング攻撃を経験しました。その週末に、彼はSSH(Secure Shell)の最初のバージョンを書き上げました。
> "私は金曜日の夜に設計を開始し、週末にプロトタイプを完成させた。月曜日には最初のユーザーがいた。" — Tatu Ylönen, 1995
SSH-1.0は以下の目標を達成しました:
- 認証: ユーザーの身元確認
- 機密性: 通信内容の暗号化
- 完全性: 改ざんの検出
- 置換透明性: telnet/rlogin/rshを置き換え可能
SSH-1 から SSH-2 へ
SSH-1には設計上の脆弱性がありました:
- CRCベースの完全性チェック(不十分)
- 鍵交換の欠陥
1996年、SSH-2が設計され、根本から再設計されました。2006年にRFC 4251-4256として標準化されました。
OpenSSH
1999年、OpenBSDプロジェクトはOpenSSHを開発しました。これはSSH-1.2.12のフリー実装から始まり、現在世界で最も広く使用されているSSH実装です。
OpenSSHは以下の原則に基づいています:
- コード監査: セキュリティ重視のコードレビュー
- 権限分離: 特権コードの最小化
- オープンソース: 透明性による信頼
SSH-2プロトコルアーキテクチャ
SSH-2は3層アーキテクチャで設計されています:
┌─────────────────────────────────────┐
│ コネクション層 │ ← チャネル多重化
│ (RFC 4254: Connection) │ リモートシェル、ポート転送
├─────────────────────────────────────┤
│ ユーザー認証層 │ ← パスワード、公開鍵認証
│ (RFC 4252: Authentication) │
├─────────────────────────────────────┤
│ トランスポート層 │ ← 鍵交換、暗号化、完全性
│ (RFC 4253: Transport) │ サーバー認証
├─────────────────────────────────────┤
│ TCP/IP │
└─────────────────────────────────────┘
4.4 SSHトランスポート層の詳細
SSH接続の確立
SSH接続は以下の段階で確立されます:
クライアント サーバー
│ │
│────── TCP接続確立(ポート22)──────→│
│ │
│←───── SSH-2.0-OpenSSH_8.9 ─────────│ バージョン交換
│────── SSH-2.0-OpenSSH_8.9 ─────────→│
│ │
│←───────── KEX_INIT ────────────────│ アルゴリズム交渉
│──────────── KEX_INIT ──────────────→│
│ │
│←──── Diffie-Hellman 鍵交換 ────────│ 共有秘密の確立
│──────────────────────────────────→│
│ │
│←───── NEW_KEYS ────────────────────│ 暗号化開始
│────── NEW_KEYS ────────────────────→│
│ │
│ 以降、すべて暗号化 │
アルゴリズム交渉
クライアントとサーバーは、使用する暗号アルゴリズムを交渉します:
交渉される項目:
1. 鍵交換アルゴリズム: curve25519-sha256, diffie-hellman-group16-sha512
2. サーバーホスト鍵アルゴリズム: ssh-ed25519, rsa-sha2-512
3. クライアント→サーバー暗号: chacha20-poly1305, aes256-gcm
4. サーバー→クライアント暗号: chacha20-poly1305, aes256-gcm
5. クライアント→サーバーMAC: hmac-sha2-512
6. サーバー→クライアントMAC: hmac-sha2-512
7. 圧縮アルゴリズム: none, zlib
各カテゴリで、クライアントとサーバーが共通してサポートする最初のアルゴリズムが選択されます。
ホスト認証
SSH接続時、クライアントはサーバーの身元を確認します。これは中間者攻撃(MITM)を防ぐために重要です:
攻撃シナリオ(ホスト認証なし):
クライアント ←───────→ 攻撃者 ←───────→ サーバー
攻撃者は両方向の
通信を復号・再暗号化
防御(ホスト認証あり):
1. サーバーは固有の秘密鍵を持つ
2. 接続時、サーバーは自分の公開鍵で署名を送信
3. クライアントはknown_hostsで公開鍵を検証
4. 攻撃者は秘密鍵を持たないため、署名を偽造できない
初回接続時の警告:
The authenticity of host 'server.example.com (192.168.1.1)' can't be established.
ED25519 key fingerprint is SHA256:xXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx.
Are you sure you want to continue connecting (yes/no)?
この警告は「Trust On First Use(TOFU)」モデルに基づいています。初回は信頼を確立し、以降の接続では検証します。
暗号化と完全性
SSH-2はEncrypt-then-MAC方式を使用します:
送信側:
1. パケットを構築
2. 暗号化: ciphertext = Encrypt(key, plaintext)
3. MAC計算: tag = MAC(key, ciphertext)
4. 送信: ciphertext || tag
受信側:
1. MACを検証(改ざん検出)
2. 検証成功なら復号
3. 復号失敗またはMAC不一致 → 接続終了
現代のSSHではAEAD(Authenticated Encryption with Associated Data)モードが推奨されます:
4.5 SSH認証メカニズム
パスワード認証
最もシンプルな認証方法ですが、いくつかの弱点があります:
クライアント サーバー
│ │
│──── SSH_MSG_USERAUTH_REQUEST ────→│
│ (method: password) │
│ (username: alice) │
│ (password: secret123) │
│ │
│←─── SSH_MSG_USERAUTH_SUCCESS ─────│ または FAILURE
弱点:
- パスワード自体はサーバーに送信される(暗号化されているが)
- ブルートフォース攻撃に脆弱
- フィッシング攻撃のリスク
- パスワード再利用の危険
公開鍵認証
より安全な認証方法です。秘密鍵がネットワークを流れることはありません:
クライアント サーバー
│ │
│ 秘密鍵を持っている 公開鍵を持っている
│ (id_ed25519) (authorized_keys)
│ │
│──── SSH_MSG_USERAUTH_REQUEST ────→│
│ (method: publickey) │
│ (公開鍵を提示) │
│ │
│←─── SSH_MSG_USERAUTH_PK_OK ───────│ 公開鍵を受け入れた
│ │
│ チャレンジ応答: │
│ 署名 = Sign(秘密鍵, セッションID + 認証データ)
│ │
│──── 署名を送信 ──────────────────→│
│ │
│ Verify(公開鍵, 署名)?
│ │
│←─── SSH_MSG_USERAUTH_SUCCESS ─────│
利点:
- 秘密鍵がネットワークに送信されない
- リプレイ攻撃に耐性(セッションIDを含む)
- パスフレーズで秘密鍵を保護可能
- 複数のサーバーで同じ鍵ペアを使用可能
鍵の種類と推奨事項
Ed25519(推奨):
- 256ビット鍵、128ビットセキュリティ
- 高速な署名と検証
- 小さな鍵と署名サイズ
- 生成: ssh-keygen -t ed25519
RSA:
- 2048ビット以上が必須(4096ビット推奨)
- 広い互換性
- 大きな鍵サイズ
- 生成: ssh-keygen -t rsa -b 4096
ECDSA(非推奨):
- NIST曲線を使用
- 実装の複雑さから避けられる傾向
認証エージェント
ssh-agentは秘密鍵をメモリに保持し、パスフレーズの繰り返し入力を避けます:
┌─────────────────────────────────────────┐
│ ユーザーセッション │
│ ┌─────────────┐ ┌────────────────┐ │
│ │ ssh client │────│ ssh-agent │ │
│ └─────────────┘ │ │ │
│ ┌─────────────┐ │ 秘密鍵1 │ │
│ │ ssh client │────│ 秘密鍵2 │ │
│ └─────────────┘ │ 秘密鍵3 │ │
│ └────────────────┘ │
└─────────────────────────────────────────┘
署名が必要な時:
1. sshクライアントがエージェントに署名を要求
2. エージェントがメモリ内の秘密鍵で署名
3. 署名をクライアントに返す
4. 秘密鍵はエージェントから出ない
4.6 ネットワークセキュリティの基礎概念
ポート番号の理論
ポート番号はトランスポート層でサービスを識別します:
0-1023: Well-known Ports(特権ポート)
root権限が必要
例: 22 (SSH), 80 (HTTP), 443 (HTTPS)
1024-49151: Registered Ports
IANAに登録されたサービス
例: 3306 (MySQL), 5432 (PostgreSQL)
49152-65535: Dynamic/Private Ports
一時的な接続に使用
SSHのデフォルトポート22は攻撃者に既知のため、自動化された攻撃の標的になります。
セキュリティ・スルー・オブスキュリティ
ポート変更はSecurity Through Obscurity(隠蔽によるセキュリティ)の一例です:
批判:
Kerckhoffsの原則(1883):
"暗号システムは、鍵以外のすべてが公開されても安全であるべき"
ポート変更だけでは根本的なセキュリティにならない
しかし:
Defense in Depth(多層防御)の一部として有効
- 自動化スキャンを回避
- 攻撃者のコストを増加
- ログノイズを削減
結論: ポート変更は追加の対策として有効だが、唯一の対策としては不十分。
脅威モデリング
Born2berootの文脈で考えられる脅威:
1. ネットワーク盗聴
対策: SSH暗号化
2. ブルートフォース攻撃
対策: 強いパスワード、公開鍵認証、fail2ban
3. 中間者攻撃
対策: ホスト鍵検証
4. 権限昇格
対策: rootログイン禁止、sudo使用
5. 未認証アクセス
対策: ファイアウォール、SSH設定
---
4.7 Born2berootのSSH設定
理論的基盤を理解したところで、Born2berootプロジェクトのSSH設定を実装します。
SSHサーバーのインストール
# パッケージリストを更新
sudo apt update
# OpenSSH Serverをインストール
sudo apt install openssh-server -y
# インストールの確認
dpkg -l | grep openssh-server
# サービスの状態確認
sudo systemctl status ssh
SSH設定ファイルの構造
# 主要な設定ファイル
/etc/ssh/sshd_config # サーバー設定
/etc/ssh/ssh_config # クライアント設定
# ホスト鍵(サーバー識別用)
/etc/ssh/ssh_host_ed25519_key # Ed25519秘密鍵
/etc/ssh/ssh_host_ed25519_key.pub # Ed25519公開鍵
/etc/ssh/ssh_host_rsa_key # RSA秘密鍵
/etc/ssh/ssh_host_rsa_key.pub # RSA公開鍵
Born2beroot必須設定
設定ファイルをバックアップしてから編集:
# バックアップ
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
# 編集
sudo vim /etc/ssh/sshd_config
1. ポート番号の変更(4242)
# 変更前:
#Port 22
# 変更後:
Port 4242
理論的根拠: 第4.6節で説明した多層防御の一部として、自動化攻撃を回避。
2. rootログインの無効化
# 変更前:
#PermitRootLogin prohibit-password
# 変更後:
PermitRootLogin no
理論的根拠: 第3章で学んだ最小権限の原則。rootは既知のユーザー名のため、攻撃の標的になりやすい。
3. 推奨セキュリティ設定
# 公開鍵認証を有効化(第4.5節の認証理論に基づく)
PubkeyAuthentication yes
# パスワード認証(公開鍵認証設定まで有効にしておく)
PasswordAuthentication yes
# 空パスワードを禁止
PermitEmptyPasswords no
# 認証試行回数を制限(ブルートフォース対策)
MaxAuthTries 3
# ログイン猶予時間を短縮
LoginGraceTime 30
設定の検証と適用
# 文法チェック(重要!)
sudo sshd -t
# エラーがなければSSHを再起動
sudo systemctl restart ssh
# ポート4242でリスニングを確認
sudo ss -tlnp | grep :4242
# 出力例: LISTEN 0 128 0.0.0.0:4242 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
4.8 VirtualBoxポートフォワーディング
NAT接続では、ホストからゲストへの直接接続はできません。ポートフォワーディングで解決します。
ネットワークアドレス変換の理解
NAT
ホストマシン ←──────────→ ゲストマシン
192.168.1.100 10.0.2.15
│ │
└──────→ VirtualBox ←─┘
NATエンジン
ポートフォワーディング:
localhost:4242 → 10.0.2.15:4242
設定方法
GUIで設定:
- VirtualBoxマネージャー → Born2berootを選択
- 設定 → ネットワーク → アダプター1 → 高度
- ポートフォワーディング → 追加(+)
- 設定:
コマンドラインで設定:
# ルールを追加
VBoxManage modifyvm "Born2beroot" --natpf1 "SSH,tcp,,4242,,4242"
# 確認
VBoxManage showvminfo "Born2beroot" | grep "NIC 1 Rule"
4.9 SSH接続テスト
ホストマシンからの接続
# 接続
ssh username@localhost -p 4242
# 初回接続時のホスト鍵確認
The authenticity of host '[localhost]:4242 ([127.0.0.1]:4242)' can't be established.
ED25519 key fingerprint is SHA256:xXxXxXxXxXxXxXxXxXxXxXxXxXxXx.
Are you sure you want to continue connecting (yes/no)? yes
これは第4.4節で説明したTOFU(Trust On First Use)モデルです。
公開鍵認証の設定
第4.5節の理論に基づき、より安全な公開鍵認証を設定します:
# ホストマシンで鍵ペア生成(Ed25519推奨)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 出力:
# Generating public/private ed25519 key pair.
# Enter file in which to save the key: [Enter]
# Enter passphrase: [強力なパスフレーズ]
# 公開鍵をサーバーにコピー
ssh-copy-id -p 4242 username@localhost
# テスト(パスフレーズで認証されるはず)
ssh username@localhost -p 4242
トラブルシューティング
接続拒否:
# SSHサービスが起動しているか確認(ゲスト内)
sudo systemctl status ssh
# ポート4242でリスニングしているか確認
sudo ss -tlnp | grep :4242
タイムアウト:
# ポートフォワーディング設定を確認
VBoxManage showvminfo "Born2beroot" | grep "NIC 1 Rule"
# 仮想マシンが起動しているか確認
VBoxManage list runningvms
4.10 SSHセキュリティ強化
fail2banによるブルートフォース対策
# インストール
sudo apt install fail2ban -y
# 設定ファイル作成
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# 編集
sudo vim /etc/fail2ban/jail.local
# SSH設定
[sshd]
enabled = true
port = 4242
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
# サービス開始
sudo systemctl start fail2ban
sudo systemctl enable fail2ban
# 状態確認
sudo fail2ban-client status sshd
fail2banは、ログを監視し、複数回認証に失敗したIPアドレスを自動的にブロックします。
4.11 理論と実践の統合
この章で学んだ概念の関係:
暗号理論
├── 対称鍵暗号 → セッション暗号化(AES, ChaCha20)
├── 公開鍵暗号 → 鍵交換、サーバー認証、ユーザー認証
│ ├── Diffie-Hellman → 共有秘密の確立
│ └── RSA/Ed25519 → 署名と検証
└── ハッシュ関数 → 完全性検証、鍵派生
SSHプロトコル
├── トランスポート層 → 暗号化、ホスト認証
├── ユーザー認証層 → パスワード/公開鍵認証
└── コネクション層 → チャネル多重化
Born2beroot実装
├── Port 4242 → 多層防御
├── PermitRootLogin no → 最小権限
├── PubkeyAuthentication → 安全な認証
└── MaxAuthTries 3 → ブルートフォース対策
4.12 次章への準備
次章ではファイアウォール(UFW)を学びます:
- パケットフィルタリングの理論
- Netfilterとiptablesのアーキテクチャ
- ステートフルファイアウォールの概念
- UFW(Uncomplicated Firewall)の設定
次章に進む前に、SSH設定が正しく動作することを確認し、スナップショットを作成してください:
# スナップショット作成
VBoxManage snapshot "Born2beroot" take "After SSH Config" \
--description "SSH configuration completed, port 4242, root login disabled"