---
title: プロトコルの進化と互換性
url: https://doc.liz6.com/ja/networking/14-protocol-design-and-evolution/02-protocol-evolution-and-compatibility
locale: ja
area: networking
tags:
- networking
- protocol-design-and-evolution
date: 2026-06-30
modified: 2026-07-16
description: プロトコルはデプロイされると変更が難しい——TCPの固定ヘッダーにより拡張に10年を要し、TLSミドルボックスの不明な拡張に対するバギーな動作がオシフィケーション（硬化）を引き起こした。QUICは設計当初からバージョンネゴシエーションとGREASE（意味のない拡張のランダム挿入）を内蔵し、ミドルボックスの硬化に対抗している——これは新プロトコルにとって必須の教訓である。
---

# プロトコルの進化と互換性

> プロトコルはデプロイされると変更が難しい——TCPの固定ヘッダーにより拡張に10年を要し、TLSミドルボックスの不明な拡張に対するバギーな動作がオシフィケーション（硬化）を引き起こした。QUICは設計当初からバージョンネゴシエーションとGREASE（意味のない拡張のランダム挿入）を内蔵し、ミドルボックスの硬化に対抗している——これは新プロトコルにとって必須の教訓である。

## 概要

プロトコルは不変ではない——デプロイされると変更が難しい。HTTP/1.1 ヘッダーのテキスト的な柔軟性は、新機能（Cache-Control, CORS）を問題なく追加することを可能にしたが、TCPの固定ヘッダーは拡張を困難にした（TCP Fast Open の普及には10年かかった）。QUICは設計当初からバージョンネゴシエーションとGREASE（意味のない拡張のランダム挿入）を内蔵しており、ミドルボックスが不明なフィールドに対して取るべきバギーな動作によるプロトコルのオシフィケーション（硬化）に対抗している。すべての新設計プロトコルは、GREASEと明確な拡張ポイントを実装すべきである。

## フォワード互換性とバックワード互換性

```
フォワード互換性 (新しいクライアント、古いサーバー):
  不明なフィールド: スキップ (protobuf, TLV)
  不明なフレームタイプ: 無視 (HTTP/2)
  → 実装: 「受け入れる側は寛容に」

バックワード互換性 (古いクライアント、新しいサーバー):
  デフォルト値での埋め合わせ
  バージョンネゴシエーション
  機能ビットマップ (TLSの暗号スイート)
```

## ネゴシエーションとフォールバック

<svg viewBox="0 0 720 320" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="三种协议协商机制:HTTP Upgrade、TLS ALPN、HTTP Alt-Svc">
  <defs>
    <marker id="nf-arrow" 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="320" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">ネゴシエーションとフォールバック: 3つのメカニズム、現在の接続を変更できるのは誰か、次回のみ変更できるのは誰か</text>

  <text x="20" y="82" font-size="12" font-weight="700" fill="#1f2933">HTTP Upgrade</text>
  <rect x="140" y="56" width="220" height="44" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="250" y="74" text-anchor="middle" font-size="11" fill="#3730a3">GET / HTTP/1.1</text>
  <text x="250" y="90" text-anchor="middle" font-size="11" fill="#3730a3">+ Upgrade: h2c</text>
  <line x1="364" y1="78" x2="396" y2="78" stroke="#475569" stroke-width="1.6" marker-end="url(#nf-arrow)"/>
  <rect x="400" y="56" width="300" height="44" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="550" y="83" text-anchor="middle" font-size="12" font-weight="600" fill="#115e59">101 Switching または 無視</text>

  <text x="20" y="146" font-size="12" font-weight="700" fill="#1f2933">TLS ALPN</text>
  <rect x="140" y="120" width="220" height="44" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="250" y="138" text-anchor="middle" font-size="11" fill="#3730a3">ClientHello</text>
  <text x="250" y="154" text-anchor="middle" font-size="11" fill="#3730a3">ALPN=[h2, http/1.1]</text>
  <line x1="364" y1="142" x2="396" y2="142" stroke="#475569" stroke-width="1.6" marker-end="url(#nf-arrow)"/>
  <rect x="400" y="120" width="300" height="44" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="550" y="147" text-anchor="middle" font-size="12" font-weight="600" fill="#115e59">ServerHello ALPN="h2"</text>

  <text x="20" y="210" font-size="12" font-weight="700" fill="#1f2933">HTTP Alt-Svc</text>
  <rect x="140" y="184" width="220" height="44" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="250" y="210" text-anchor="middle" font-size="11" fill="#3730a3">Alt-Svc: h3=":443"</text>
  <line x1="364" y1="206" x2="396" y2="206" stroke="#475569" stroke-width="1.6" marker-end="url(#nf-arrow)"/>
  <rect x="400" y="184" width="300" height="44" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="550" y="202" text-anchor="middle" font-size="11.5" font-weight="600" fill="#115e59">次回接続で HTTP/3 を使用</text>
  <text x="550" y="218" text-anchor="middle" font-size="10.5" fill="#0f766e">(現在の接続はアップグレードしない)</text>

  <rect x="40" y="248" width="640" height="54" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="56" y="270" font-size="12.5" fill="#115e59">HTTP Upgrade と TLS ALPN はどちらも同一接続内でのリアルタイムネゴシエーションですが、Alt-Svc は「次回プロトコルを変更する」ためのヒントに過ぎません——</text>
  <text x="56" y="289" font-size="12.5" fill="#115e59">現在の接続はアップグレードされず、これこそが「ネゴシエーション」と「フォールバック」の違いです。</text>
</svg>

## GREASE

```
問題: ミドルボックス (ファイアウォール、NAT) は自分が知っているバイトパターンしか認識しない
  → 新しいプロトコル拡張 → 認識できないため破棄される → プロトコルが進化できない

GREASE: クライアントが意味のない拡張/値をランダムに挿入する:
  TLS: ClientHello 内のランダムな暗号スイート
  HTTP/2: ランダムな SETTINGS パラメータ
  QUIC: ランダムなトランスポートパラメータ

目的: ミドルボックスが不明な値を正しく処理する必要がある (無視すること。拒否してはならない)
  → 将来の本当の拡張がミドルボックスによってブロックされない
```

## QUIC の教訓

<svg viewBox="0 0 720 380" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="TCP 的四类历史教训如何应用到 QUIC 设计">
  <defs>
    <marker id="ql-arrow" 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="380" fill="#ffffff"/>
  <text x="360" y="26" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">QUIC の教訓: TCPの4つの古い問題を一つずつ逆手に取った設計</text>

  <rect x="44" y="44" width="310" height="56" rx="6" fill="#e2e8f0"/>
  <text x="58" y="66" font-size="12" font-weight="700" fill="#334155">① ヘッダーの平文</text>
  <text x="58" y="84" font-size="10.5" fill="#64748b">→ ミドルボックスによる改ざん → オシフィケーション</text>
  <line x1="354" y1="72" x2="392" y2="72" stroke="#475569" stroke-width="1.6" marker-end="url(#ql-arrow)"/>
  <rect x="392" y="44" width="284" height="56" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="406" y="66" font-size="12" font-weight="700" fill="#115e59">QUIC: フラグはすべて暗号化</text>
  <text x="406" y="84" font-size="10.5" fill="#0f766e">ミドルボックスは Connection ID しか見えない</text>

  <rect x="44" y="110" width="310" height="56" rx="6" fill="#e2e8f0"/>
  <text x="58" y="132" font-size="12" font-weight="700" fill="#334155">② バージョンネゴシエーションの欠如</text>
  <text x="58" y="150" font-size="10.5" fill="#64748b">→ 進化が鈍い</text>
  <line x1="354" y1="138" x2="392" y2="138" stroke="#475569" stroke-width="1.6" marker-end="url(#ql-arrow)"/>
  <rect x="392" y="110" width="284" height="56" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="406" y="132" font-size="12" font-weight="700" fill="#115e59">QUIC: バージョンは最初のパケットに含まれる</text>
  <text x="406" y="150" font-size="10.5" fill="#0f766e">サーバーは拒否して他のバージョンを提案できる</text>

  <rect x="44" y="176" width="310" height="56" rx="6" fill="#e2e8f0"/>
  <text x="58" y="198" font-size="12" font-weight="700" fill="#334155">③ 5-tuple へのバインディング</text>
  <text x="58" y="216" font-size="10.5" fill="#64748b">→ NAT リバインディング → 接続切断</text>
  <line x1="354" y1="204" x2="392" y2="204" stroke="#475569" stroke-width="1.6" marker-end="url(#ql-arrow)"/>
  <rect x="392" y="176" width="284" height="56" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="406" y="198" font-size="12" font-weight="700" fill="#115e59">QUIC: Connection ID</text>
  <text x="406" y="216" font-size="10.5" fill="#0f766e">IP / ポートに依存しない</text>

  <rect x="44" y="242" width="310" height="56" rx="6" fill="#e2e8f0"/>
  <text x="58" y="270" font-size="12" font-weight="700" fill="#334155">④ 拡張の検出</text>
  <line x1="354" y1="270" x2="392" y2="270" stroke="#475569" stroke-width="1.6" marker-end="url(#ql-arrow)"/>
  <rect x="392" y="242" width="284" height="56" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="406" y="264" font-size="12" font-weight="700" fill="#115e59">QUIC: GREASE を内蔵</text>
  <text x="406" y="282" font-size="10.5" fill="#0f766e">すべての QUIC 実装に組み込まれている</text>

  <rect x="40" y="310" width="640" height="54" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="56" y="332" font-size="12.5" fill="#3730a3">4つの教訓に共通する論理は、TCPを硬化させた「平文」「ネゴシエーションの欠如」「アドレスへのバインディング」「拡張の検出」といった設計を、</text>
  <text x="56" y="351" font-size="12.5" fill="#3730a3">QUIC では一つずつ逆手に取っている——これが「プロトコルの進化」という科目の必修内容である。</text>
</svg>

## 参考

- **GREASE**: RFC 8701
- **QUIC Appendix A**: RFC 9000 (design rationale)

*Keywords: forward compatibility, backward compatibility, GREASE, ossification, QUIC, Alt-Svc*
