---
title: SSH プロトコル
url: https://doc.liz6.com/ja/networking/12-security-protocols/01-ssh-protocol
locale: ja
area: networking
tags:
- networking
- security-protocols
date: 2026-06-30
modified: 2026-07-16
description: SSH は単なる「暗号化された telnet」ではない——トランスポート層（鍵交換＋暗号化）、認証層（公開鍵/パスワード/証明書）、接続層（ポートフォワーディング/X11/SFTP のマルチプレクシング）の 3 層が分離されている。ポートフォワーディングにより、SSH は「スイスアーミーナイフ」のような存在となる。
---

# SSH プロトコル

> SSH は単なる「暗号化された telnet」ではない——トランスポート層（鍵交換＋暗号化）、認証層（公開鍵/パスワード/証明書）、接続層（ポートフォワーディング/X11/SFTP のマルチプレクシング）の 3 層が分離されている。ポートフォワーディングにより、SSH は「スイスアーミーナイフ」のような存在となる。

## 概要

SSH（Secure Shell, 1995/2006）は Unix/Linux システム管理の中核ツールである。プロトコルは 3 層に分かれている：Transport Layer は鍵交換と暗号化を行い、User Authentication Layer は身份認証（公開鍵/パスワード/TOTP）を行い、Connection Layer は単一の TCP 接続上で shell/port forwarding/SFTP などのチャネルをマルチプレクシングする。SSH のポートフォワーディング（-L/-R）は簡易 VPN として機能し、暗号化トンネルを通じてリモートポートをローカルにマッピングできる。SSH 2.0 は SSH 1.x の重大なセキュリティ問題を修正したものであり、現代において唯一安全なバージョンである。

## 3 層アーキテクチャ

```
Connection Protocol (RFC 4254):  channels (shell, exec, forward, SFTP)
User Authentication (RFC 4252):  password, publickey, keyboard-interactive
Transport Layer (RFC 4253):      key exchange, encryption, server auth
TCP
```

## Transport Layer: 鍵交換 (curve25519-sha256)

<svg viewBox="0 0 720 330" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="SSH 鍵交換の5ステップ：バージョン交換、アルゴリズム合意、DH交換、鍵導出、ホスト認証">
  <defs><marker id="sshkexah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="330" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">SSH 鍵交換の5ステップ (curve25519-sha256)</text>

  <rect x="24" y="48" width="214" height="26" rx="6" fill="#4f46e5"/>
  <text x="131" y="65" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">① 接続確立とアルゴリズム合意</text>
  <rect x="258" y="48" width="214" height="26" rx="6" fill="#0d9488"/>
  <text x="365" y="65" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">② DH 鍵交換</text>
  <rect x="492" y="48" width="204" height="26" rx="6" fill="#22c55e"/>
  <text x="594" y="65" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">③ 鍵導出とホスト認証</text>
  <line x1="238" y1="61" x2="258" y2="61" stroke="#475569" stroke-width="1.6" marker-end="url(#sshkexah)"/>
  <line x1="472" y1="61" x2="492" y2="61" stroke="#475569" stroke-width="1.6" marker-end="url(#sshkexah)"/>

  <rect x="32" y="86" width="198" height="46" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="131" y="103" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">バージョン交換</text>
  <text x="131" y="121" text-anchor="middle" font-size="10" fill="#4f46e5">C ↔ S で SSH-2.0-OpenSSH_9.6 を交換</text>
  <rect x="32" y="140" width="198" height="56" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="131" y="157" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">アルゴリズム合意 (KEXINIT)</text>
  <text x="131" y="174" text-anchor="middle" font-size="10" fill="#4f46e5">候補リスト: kex / host_key</text>
  <text x="131" y="188" text-anchor="middle" font-size="10" fill="#4f46e5">暗号化アルゴリズム / MAC アルゴリズム</text>

  <rect x="266" y="86" width="198" height="46" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="365" y="103" text-anchor="middle" font-size="12" font-weight="700" fill="#115e59">C → S: KEX_ECDH_INIT</text>
  <text x="365" y="121" text-anchor="middle" font-size="10" fill="#0f766e">一時公開鍵 Q_C を送信</text>
  <rect x="266" y="140" width="198" height="66" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="365" y="157" text-anchor="middle" font-size="12" font-weight="700" fill="#115e59">S → C: KEX_ECDH_REPLY</text>
  <text x="365" y="174" text-anchor="middle" font-size="10" fill="#0f766e">K_S (サーバー公開鍵) + Q_S (一時公開鍵)</text>
  <text x="365" y="188" text-anchor="middle" font-size="10" fill="#0f766e">H に対する署名で秘密鍵の所持を証明</text>

  <rect x="500" y="86" width="188" height="58" rx="6" fill="#dcfce7" stroke="#4ade80"/>
  <text x="594" y="103" text-anchor="middle" font-size="12" font-weight="700" fill="#166534">共有秘密鍵の計算</text>
  <text x="594" y="121" text-anchor="middle" font-size="10" fill="#15803d">shared secret → H = session_id</text>
  <text x="594" y="135" text-anchor="middle" font-size="10" fill="#15803d">IV / 暗号化鍵 / MAC 鍵 (双方向) を導出</text>
  <rect x="500" y="154" width="188" height="66" rx="6" fill="#ffedd5" stroke="#f97316"/>
  <text x="594" y="171" text-anchor="middle" font-size="12" font-weight="700" fill="#9a3412">クライアントによる K_S の検証</text>
  <text x="594" y="188" text-anchor="middle" font-size="10" fill="#c2410c">初回接続: 指紋を確認</text>
  <text x="594" y="202" text-anchor="middle" font-size="10" fill="#c2410c">known_hosts に書き込み/照合</text>

  <rect x="40" y="242" width="640" height="70" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="360" y="264" text-anchor="middle" font-size="12.5" fill="#3730a3">検証順序が重要である：署名によりまずサーバーが K_S 秘密鍵を所持していることを証明し、known_hosts の照合で中間者攻撃を防ぐ。</text>
  <text x="360" y="284" text-anchor="middle" font-size="12.5" fill="#3730a3">初回接続の信頼は TOFU (Trust On First Use) に依存する——これは SSH において自動化検証が唯一不可能な箇所である。</text>
</svg>

## User Authentication

```
方法 (順序で試行):
  1. publickey: クライアント: sign(session_id + request + publickey, privatekey)
     サーバー: verify → SSH_MSG_USERAUTH_SUCCESS
  2. keyboard-interactive: TOTP または challenge-response
  3. password: 暗号化チャネル内で送信 (安全)
```

## Connection Layer: チャネルマルチプレクシング

```
各チャネルは独立:
  SSH_MSG_CHANNEL_OPEN: type="session" → channel 0
  SSH_MSG_CHANNEL_OPEN: type="direct-tcpip" → channel 1 (ポートフォワーディング)

チャネルタイプ:
  session:         shell, exec, subsystem (SFTP)
  direct-tcpip:    ローカルポートフォワーディング (-L)
  forwarded-tcpip: リモートポートフォワーディング (-R)
```

## ポートフォワーディング

```
ローカル (-L 8080:internal:80): SSH クライアントが :8080 でリッスン → トンネル → SSH サーバーが internal:80 に接続
リモート (-R 3000:localhost:22): SSH サーバーが :3000 でリッスン → トンネル → SSH クライアントが localhost:22 に接続
```

## 参考

- **RFC**: 4251-4254, 5656, 8731
- **ソースコード**: OpenSSH (`sshconnect2.c` for auth, `channels.c` for channels)

*Keywords: SSH, transport, kex, publickey, channel, port forwarding, SFTP, known_hosts*
