【テクニカル・上級編】 TCPのシーケンス番号と確認応答番号による信頼性制御 – ネットワーク基礎とWebセキュリティ実践ガイド

TCPの「信頼」という名の呪縛:シーケンス番号が支配するパケットの深淵

ネットワークエンジニアとして現場に立つと、OSI参照モデルの教科書的な記述がいかに「理想」でしかないかを痛感させられる。特にTCPの信頼性制御――シーケンス番号(SEQ)と確認応答番号(ACK)のやり取り――は、一見すると堅牢な握手に見えるが、その裏では、パケットロスという「カオス」と、高遅延という「物理的な制約」との終わりなき戦いが繰り広げられている。

今回は、TCPの心臓部であるシーケンス制御を軸に、現代のインフラアーキテクトが知っておくべき「パケットの真実」を紐解いていく。

—

1. シーケンス番号とACK:それは「次」への約束

TCPの信頼性は、単純明快なロジックの上にある。
送信側が投げたデータの先頭バイト位置を示す SEQ と、受信側が「ここまで受け取った。次はここからくれ」と要求する ACK 番号。この2つの数字が同期し続けることで、我々は信頼性のないIPネットワーク上で、信頼性の高いストリーム通信を実現している。

しかし、ここで忘れてはならないのは、ACK 番号が「最後に受け取った番号」ではなく「次に期待するシーケンス番号」を指すという点だ。

  • SEQ=1001, LEN=500 を受け取った側は、データが1001から1500までであることを認識し、ACK=1501 を返す。
  • この ACK の背後には、TCPバッファが常に「欠落はないか?」「順序は正しいか?」を監視し続けるという計算資源のコストが隠れている。

この「期待値の整合性」が崩れたとき、ネットワークは再送制御(Retransmission)という名の低速なループに陥る。

—

2. 現場の現実:RTT削減とカーネルチューニング

モダンな Web サービスにおいて、TCPの信頼性制御は「遅延のボトルネック」になり得る。RTT(Round Trip Time)を短縮し、スループットを最大化するためには、カーネルパラメータの最適化が避けては通れない。

特に高遅延環境や大容量通信では、デフォルトのTCPウィンドウサイズでは不十分だ。パケットが届く前にバッファが溢れれば、ACKが戻るまで通信が止まる。

以下の設定は、現代的なバックエンドサーバーで検討すべきチューニングの一例だ。

# TCPウィンドウサイズを拡張し、帯域幅遅延積(BDP)を最大化する
# メモリに余裕がある環境では必須の設定
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"

# TCP選択的確認応答(SACK)の有効化
# パケットロス発生時に、失われたパケットだけを効率的に再送させる
sysctl -w net.ipv4.tcp_sack=1

# TCPウィンドウ拡大オプションの有効化
# 64KBを超えるウィンドウサイズを扱うために不可欠
sysctl -w net.ipv4.tcp_window_scaling=1

SACK(Selective ACK)は、現代のネットワークにおいて必須のオプションだ。これが無効だと、パケットが一つ欠けただけで受信側は「それ以降のデータも全部再送しろ」という効率の悪い要求を出すことになる。

—

3. TLSハンドシェイクとTCPの「悲劇的な出会い」

セキュリティの観点から欠かせないのがTLSだ。しかし、TLSハンドシェイクはTCPの3ウェイ・ハンドシェイクの上にさらに数往復のデータを重ねる。

TCP SYN → SYN/ACK → ACK の後に、TLS Client Hello が飛ぶ。ここでパケットロスが発生すると、TCP層での再送だけでなく、アプリケーション層でのTLSハンドシェイクのタイムアウトが重なり、ユーザー体験は劇的に悪化する。

これを回避するための現代的な解は、以下の2点に集約される。

1. TLS 1.3の採用: 0-RTT(Zero Round Trip Time)ハンドシェイクにより、初回のセッション再開でデータを送信可能にする。
2. TCP Fast Open (TFO): SYN パケットにデータを埋め込み、最初のハンドシェイクでデータ送信を開始する。

# TCP Fast Openを有効化する(サーバー側)
# 0: 無効, 1: クライアントのみ, 2: サーバーのみ, 3: 両方
sysctl -w net.ipv4.tcp_fastopen=3

—

4. セキュリティスペシャリストが警告する「シーケンス番号の脆弱性」

古来より、TCPのシーケンス番号を推測する攻撃(TCP Sequence Prediction Attack)が存在した。現在のOSはランダムな初期シーケンス番号(ISN)を生成するようになっているため、単純な割り込みは困難だが、依然として脆弱性は残っている。

  • パケットインジェクション: ACK 番号を偽装してセッションを乗っ取る手法。
  • TCPリセット攻撃: 正しいシーケンス番号を推測し、強制的に RST を送って接続を切断させる。

これらへの対策は、もはやネットワーク層単体では完結しない。ゼロトラストの思想に基づき、TCPレイヤーの正当性に依存せず、アプリケーション層でJWT(JSON Web Token)によるセッション検証を行うこと、そして相互TLS(mTLS)でパケットそのものの暗号化と認証を行うことが、現代の防衛線の要となっている。

—

結びに:パケットを「視る」力を養え

エンジニアが「繋がらない」「遅い」というトラブルに直面したとき、まずやるべきは tcpdump を叩き、シーケンス番号の推移を Wireshark で眺めることだ。

SEQ が飛んでいないか? ACK が送られてくるまでに異常な時間がかかっていないか? パケットのヘッダーには、その通信の「体調」がすべて刻まれている。教科書的な知識を捨て、パケットの呼吸を感じ取れるようになったとき、君たちは真のネットワークスペシャリストへと一歩近づくはずだ。

次にパケットロスに遭遇したとき、それは単なるエラーではなく、ネットワークが君たちに送っている「チューニングの招待状」だと受け取ってほしい。

コメント

タイトルとURLをコピーしました