RFC 2818 - HTTP Over TLS (HTTPS)
ステータス: 情報提供文書
著者: E. Rescorla (RTFM, Inc.)
発行日: 2000年5月
概要 (Abstract)
本文書は、インターネット上でHTTP接続を保護するためにTLSを使用する方法を説明します。現在の実践では、HTTPをSSL (TLSの前身) 上に重ね、異なるサーバーポートを使用することで、安全なトラフィックと非安全なトラフィックを区別しています。本文書は、TLSを使用したこの実践を文書化するものです。
重要性
RFC 2818はWeb セキュリティの基盤です:
- 🔒 HTTPSの基本メカニズムを定義
- 🌐 すべての現代的なウェブサイトのセキュリティ基盤
- 🔑 証明書検証とアイデンティティ識別
- ⚡ セキュアな接続の確立と終了
1. Introduction (序論)
HTTP [RFC2616] は当初、インターネット上で平文で使用されていました。しかし、機密性の高いアプリケーションでのHTTPの使用が増加したことで、セキュリティ対策が必要となりました。SSLおよびその後継であるTLS [RFC2246] は、チャネル指向のセキュリティを提供するように設計されました。本文書は、TLS上でHTTPを使用する方法を説明します。
中核概念
HTTPS = HTTP + TLS
┌────────────────────────────────────────┐
│ HTTP/1.1 Protocol │
│ (Application Layer Protocol) │
├────────────────────────────────────────┤
│ TLS/SSL Protocol │
│ (Transport Layer Security) │
├────────────────────────────────────────┤
│ TCP Protocol │
│ (Transmission Control Protocol) │
└────────────────────────────────────────┘
1.1. Requirements Terminology (要件用語)
本文書に出現するキーワード「しなければならない (MUST)」、「してはならない (MUST NOT)」、「必須である (REQUIRED)」、「すべきである (SHOULD)」、「すべきでない (SHOULD NOT)」、および「してもよい (MAY)」は、[RFC2119] で説明されているとおりに解釈されるものとします。
2. HTTP Over TLS (TLS上のHTTP)
中核原則
概念的には非常にシンプル: HTTP/TLSは非常にシンプルです。TCPでHTTPを使用するのとまったく同じように、TLS上でHTTPを使用します。
2.1. Connection Initiation (接続の開始)
プロセス:
1. クライアント → サーバー: TCP接続を確立 (ポート443)
2. クライアント → サーバー: TLS ClientHelloを送信
3. ↔ TLSハンドシェイクプロセス ↔
4. ハンドシェイク完了後: クライアントは最初のHTTPリクエストを開始できます
要件:
- ✅ HTTPクライアントはTLSクライアントとして動作しなければならない (MUST)
- ✅ 適切なポートに接続する (デフォルト443)
- ✅ ハンドシェイクを開始するためにTLS ClientHelloを送信する
- ✅ すべてのHTTPデータは、TLS「アプリケーションデータ」として送信されなければならない (MUST)
フロー例:
クライアント:
1. www.example.com:443にTCP接続
2. ClientHelloを送信
サーバー:
3. ServerHello + 証明書を応答
4. ServerHelloDone
クライアント:
5. ClientKeyExchange
6. ChangeCipherSpec
7. Finished
サーバー:
8. ChangeCipherSpec
9. Finished
← TLSハンドシェイク完了 →
クライアント:
10. 暗号化されたHTTPリクエストを送信:
GET / HTTP/1.1
Host: www.example.com
2.2. Connection Closure (接続の終了)
TLSは、セキュアな接続終了のための機能を提供します。
Closure Alert (終了アラート)
定義:
- 有効な終了 (Valid Closure): 適切な終了アラートを受信
- 不完全な終了 (Incomplete Close): 終了アラート送信後すぐに接続を終了
- 早期終了 (Premature Close): 終了アラートを受信せずに接続を終了
要件:
- ✅ 実装は接続を終了する前に終了アラート交換を開始しなければならない (MUST)
- ⚠️ 実装は終了アラート送信後に接続を終了してもよい (MAY) (待機せずに)
- ❌ 早期終了を受信した接続はセッションを再利用してはならない (MUST NOT)
2.2.1. Client Behavior (クライアントの動作)
問題: HTTPは接続終了を使用してサーバーデータの終了を通知します。
クライアントは以下を行わなければならない (MUST):
- ✅ すべての早期終了をエラーとして扱う
- ✅ 受信したデータを切り捨てられた可能性があるものとして扱う
- ✅ 接続を終了する前に終了アラートを送信する
特殊なケース:
- Content-Lengthのないレスポンス:
HTTP/1.1 200 OK
Content-Type: text/html
[接続終了が終わりを示す]
← 早期終了がサーバーによるものか攻撃者によるものか区別できない →
- Content-Lengthが存在するが完全に読み取られていない場合:
HTTP/1.1 200 OK
Content-Length: 1000
[終了前に500バイトのみ受信]
← サーバーエラーか攻撃かを判断できない →
例外: 受信したデータがContent-Lengthと一致する場合は、完了として扱うべきである (SHOULD)。
クライアント例:
✅ 通常の終了:
クライアント: closure_alertを送信
サーバーのclosure_alertを待機
接続を終了
⚡ 高速終了:
クライアント: closure_alertを送信
すぐに接続を終了 (待機しない)
← これによりサーバー側で不完全な終了が発生 →
2.2.2. Server Behavior (サーバーの動作)
RFC 2616の要件: サーバーはクライアントの終了から適切に回復しなければならない (MUST)。
サーバーは以下を行うべきである (SHOULD):
- ✅ クライアントからの不完全な終了を受け入れる準備をする
- ✅ このように終了されたTLSセッションの再開を許可する
- ✅ クライアントと終了アラートを交換しようとする
- ⚡ 終了アラート送信後に接続を終了してもよい (MAY)
実装注意事項:
持続的な接続を使用しないHTTP:
- サーバーは接続終了によってデータの終わりを通知
- しかし、クライアントはすでに終了アラートを送信し切断している可能性がある
2.3. Port Number (ポート番号)
デフォルトポート: 443
理論的根拠:
HTTPサーバーが期待: Request-Line (例: GET / HTTP/1.1)
TLSサーバーが期待: ClientHello
← 同じポートでは区別できない →
解決策: 異なるポートを使用
- HTTP: 80
- HTTPS: 443
例:
# HTTP (平文)
curl http://www.example.com:80/
# HTTPS (暗号化)
curl https://www.example.com:443/
2.4. URI Format (URI形式)
プロトコル識別子: https:// (http://の代わり)
例:
https://www.example.com/~smith/home.html
https://api.example.com:8443/v1/users
https://192.168.1.1/admin
URIコンポーネント:
https://www.example.com:443/path?query#fragment
↑ ↑ ↑ ↑ ↑ ↑
scheme host port path query fragment
3. Endpoint Identification (エンドポイント識別)
3.1. Server Identity (サーバーアイデンティティ)
中核要件: クライアントは中間者攻撃を防ぐために、サーバーのアイデンティティを検証しなければならない (MUST)。
アイデンティティ検証プロセス
1. クライアントはURIからホスト名を取得
例: https://www.example.com
2. サーバーはTLSハンドシェイクで証明書を提供
3. クライアントはホスト名が証明書のアイデンティティと一致するか確認
アイデンティティフィールドの優先順位
優先順位1: subjectAltName (主体別名)
証明書内のsubjectAltName拡張 (dNSNameタイプ):
dNSName: www.example.com
dNSName: api.example.com
← このフィールドを使用しなければならない (MUST) (存在する場合) →
優先順位2: Common Name (共通名)
証明書のSubjectフィールド内のCN:
CN=www.example.com
← subjectAltNameがない場合のみ使用 →
← 非推奨、CAはdNSNameを使用すべきである →
マッチングルール
1. ワイルドカードマッチング:
証明書: *.example.com
✅ マッチ: foo.example.com
❌ マッチしない: bar.foo.example.com
証明書: f*.com
✅ マッチ: foo.com
❌ マッチしない: bar.com
2. IPアドレス:
URI: https://192.168.1.1/
証明書は以下を含む必要がある (MUST): iPAddress subjectAltName
値は正確に一致する必要がある (MUST): 192.168.1.1
3. 複数のアイデンティティ:
証明書が複数のdNSNameを含む場合:
- www.example.com
- api.example.com
- *.app.example.com
← いずれか1つにマッチすれば許容される →
マッチしない場合の動作
ユーザー指向クライアント (ブラウザ):
- ✅ ユーザーに通知しなければならない (MUST)
- ⚠️ ユーザーに続行のオプションを提供してもよい (MAY)
- または接続を終了
自動化クライアント (APIクライアント):
- ✅ 監査ログにエラーを記録しなければならない (MUST)
- ✅ 接続を終了すべきである (SHOULD)
- ⚠️ チェックを無効にする設定オプションを提供してもよい (MAY)
セキュリティ警告
信頼できないURIソース:
攻撃シナリオ:
1. ユーザーがHTTPページ内のリンクをクリック
2. HTTPページ自体は暗号化されていない
3. 中間者がURIを置き換えた可能性がある
防御:
ユーザーはサーバー証明書を注意深く確認すべきである
3.2. Client Identity (クライアントアイデンティティ)
通常の場合: サーバーはクライアントのアイデンティティに関する外部知識を持ちません。
サーバーが外部知識を持つ場合 (HTTPまたはTLS外から):
- 上記のようにアイデンティティを確認すべきである (SHOULD)
クライアント証明書認証:
一般的なシナリオ:
- 企業内部システム
- APIアクセス制御
- 相互TLS (mTLS)
検証:
- 適切なCAにルート化された証明書チェーン
- オプション: 特定のクライアントアイデンティティを検証
Security Considerations (セキュリティに関する考察)
本文書全体がセキュリティに関するものです。
主要なセキュリティポイント
-
証明書検証は必須である (Mandatory)
- クライアントはサーバー証明書を検証しなければならない (MUST)
- 中間者攻撃を防止
-
適切な接続終了 (Proper Connection Closure)
- TLS終了アラートを使用
- データ切り捨て攻撃を検出
-
ホスト名検証 (Hostname Verification)
- 証明書置換攻撃を防止
- CNよりsubjectAltNameを優先
-
信頼できないURIに注意 (Beware Untrusted URIs)
- HTTP経由で取得されたURIは改ざんされている可能性がある
- ユーザーは証明書を確認すべきである
実践例
完全なHTTPS接続
クライアント操作:
1. URIを解析: https://www.example.com/page.html
→ ホスト名: www.example.com
→ ポート: 443 (デフォルト)
2. www.example.com:443にTCP接続
3. TLSハンドシェイク:
ClientHello →
← ServerHello + Certificate
証明書内のホスト名を検証
...ハンドシェイク完了...
4. 暗号化されたHTTPリクエストを送信:
GET /page.html HTTP/1.1
Host: www.example.com
5. 暗号化されたHTTPレスポンスを受信:
HTTP/1.1 200 OK
Content-Length: 1234
...
6. 接続を終了:
closure_alertを送信
TCP接続を終了
証明書検証の例
# Python例 (概念的)
import ssl
import socket
# SSLコンテキストを作成
context = ssl.create_default_context()
# サーバーに接続
sock = socket.create_connection(('www.example.com', 443))
ssock = context.wrap_socket(sock, server_hostname='www.example.com')
# wrap_socketは自動的に以下を検証:
# 1. 証明書チェーンが有効
# 2. ホスト名が一致
# 3. 証明書が期限切れでない
# 証明書情報を取得
cert = ssock.getpeercert()
print(f"Subject: {cert['subject']}")
print(f"Issuer: {cert['issuer']}")
print(f"SANs: {cert.get('subjectAltName', [])}")
一般的なエラー処理
エラー1: 証明書ホスト名不一致
Certificate Hostname Mismatch
- 証明書: *.example.com
- アクセス: www.different.com
→ 接続を終了またはユーザーに警告
エラー2: 証明書期限切れ
Certificate Expired
- Not After: 2023-12-31
- 現在: 2024-01-01
→ 接続を拒否
エラー3: 自己署名証明書
Self-Signed Certificate
- 信頼されたCAリストにない
→ ユーザーに警告または拒否
エラー4: 不完全な証明書チェーン
Incomplete Certificate Chain
- 中間証明書が欠落
→ 検証できない、接続を拒否
現代標準との関係
RFC 2818の後継
RFC 2818は依然として有効ですが、更新された仕様があります:
| RFC | タイトル | 説明 |
|---|---|---|
| RFC 2818 | HTTP Over TLS | 本文書 (2000年) |
| RFC 5246 | TLS 1.2 | 更新されたTLSプロトコル |
| RFC 8446 | TLS 1.3 | 最新のTLSプロトコル |
| RFC 6125 | 証明書検証 | より詳細なホスト名検証 |
| RFC 7230-7235 | HTTP/1.1 | 更新されたHTTP仕様 |
| RFC 7540 | HTTP/2 | HTTP/2は通常TLS上で実行 |
現代的な実践の更新
- TLSバージョン:
RFC 2818: SSL/TLS (1.0/1.1)
現代: TLS 1.2+ (TLS 1.0/1.1は非推奨)
- 証明書検証:
RFC 2818: 基本ルール
RFC 6125: 詳細な仕様
- HSTS:
RFC 6797: HTTP Strict Transport Security
ブラウザに強制的にHTTPSを使用させる
クイックリファレンス
HTTPS vs HTTP
| 機能 | HTTP | HTTPS |
|---|---|---|
| プロトコル | http:// | https:// |
| ポート | 80 | 443 |
| 暗号化 | ❌ 平文 | ✅ TLS暗号化 |
| 完全性 | ❌ 保護なし | ✅ MAC保護 |
| 認証 | ❌ サーバー認証なし | ✅ 証明書認証 |
| プライバシー | ❌ 盗聴可能 | ✅ 暗号化通信 |
TLSハンドシェイク概要
クライアント サーバー
| |
|--- ClientHello --------------->|
| |
|<-- ServerHello, Certificate ---|
|<-- ServerHelloDone ------------|
| |
|--- ClientKeyExchange --------->|
|--- ChangeCipherSpec ---------->|
|--- Finished ------------------>|
| |
|<-- ChangeCipherSpec -----------|
|<-- Finished -------------------|
| |
|=== 暗号化チャネル確立 =========|
| |
|--- 暗号化HTTPリクエスト ------->|
|<-- 暗号化HTTPレスポンス --------|
一般的なツール
# OpenSSLで証明書を表示
openssl s_client -connect www.example.com:443 -showcerts
# TLSバージョンをテスト
openssl s_client -connect www.example.com:443 -tls1_2
# 証明書の詳細を表示
echo | openssl s_client -connect www.example.com:443 2>/dev/null | \
openssl x509 -noout -text
# cURLでHTTPSを使用
curl -v https://www.example.com
References (参考文献)
規範的参考文献
- [RFC 2119] - RFCで要件レベルを示すために使用するキーワード
- [RFC 2246] - TLSプロトコル
- [RFC 2459] - インターネットX.509公開鍵基盤証明書およびCRLプロファイル
- [RFC 2616] - ハイパーテキスト転送プロトコル -- HTTP/1.1
情報的参考文献
- [RFC 2817] - HTTP/1.1内でのTLSへのアップグレード
- [RFC 5246] - トランスポート層セキュリティ (TLS) プロトコルバージョン1.2
- [RFC 6125] - ドメインベースのアプリケーションサービスアイデンティティの表現と検証
- [RFC 6797] - HTTP Strict Transport Security (HSTS)
- [RFC 7230-7235] - ハイパーテキスト転送プロトコル (HTTP/1.1) 更新仕様
- [RFC 8446] - トランスポート層セキュリティ (TLS) プロトコルバージョン1.3
用語集 (Glossary)
中核用語
TLS (Transport Layer Security)
- トランスポート層セキュリティプロトコル、SSLの後継
SSL (Secure Sockets Layer)
- TLSの前身、現在は非推奨
Certificate (証明書)
- 公開鍵とアイデンティティ情報を含むデジタル文書
CA (Certificate Authority / 証明機関)
- 信頼できる証明書を発行する証明機関
Closure Alert (終了アラート)
- セキュアな接続終了のためのTLSメカニズム
Premature Close (早期終了)
- 不適切なTLS接続の終了
Man-in-the-Middle Attack (中間者攻撃)
- 攻撃者が通信を傍受し、潜在的に変更する攻撃
subjectAltName (主体別名)
- 追加のホスト名を指定する証明書拡張
Common Name (共通名)
- 証明書サブジェクト内のCNフィールド
戻る: RFCドキュメントリスト
関連RFC: