# TCPセッションハイジャック・RSTインジェクション・IPスプーフィングの仕組みと防御【2026】— RFC 5961/6528/BCP 38

> 確立済みの TCP 接続を奪う/切るセッションハイジャック・RST インジェクションと、送信元を偽る IP スプーフィングを、シーケンス番号の原理から RFC 5961（challenge ACK）・RFC 6528（ISN ランダム化）・BCP 38（ingress filtering）の防御まで体系的に解説。なぜ盲目的注入が成立し、なぜ現代では難しいのかを TCP の状態遷移から説明し、TLS による無害化まで型安全なコードで示します。すべて隔離ラボに閉じた合法手順です。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: セキュリティ, ネットワーク, TCP/IP, TCP, 脆弱性診断, ホワイトハッカー
- URL: https://tomodahinata.com/blog/tcp-session-hijacking-rst-injection-ip-spoofing-defense-guide
- カテゴリ: 実践ネットワーク攻撃と防御
- 総合ガイド: https://tomodahinata.com/blog/network-penetration-testing-methodology-attack-defense-guide

## 要点

- TCPセッションハイジャックは確立済み接続に正しいシーケンス番号のセグメントを割り込ませて乗っ取る攻撃。RSTインジェクションは偽の RST で接続を強制切断する（検閲・妨害に悪用される）
- 成立の鍵はシーケンス番号。経路上（MITM済み）なら番号は見えるので容易。経路外（blind）からは番号の推測が必要で、ウィンドウサイズ次第で現実的になりうるのが脅威だった
- IPスプーフィングは送信元IPを詐称する。盲目的攻撃・DDoSの反射増幅・信頼ベース認可の回避に使われる。TCPでは ISN を当てられない限り接続を完遂できないのが歯止め
- 防御①：RFC 6528 の ISN 暗号的ランダム化で番号推測を封じる。RFC 5961 の challenge ACK で盲目的 RST/SYN 注入を大幅に困難化（ACK スロットリング付き）
- 防御②：BCP 38（RFC 2827）の ingress filtering で詐称送信元を経路で落とす。そして最終防壁は TLS——番号を奪われても、暗号化・完全性・認証で中身は守られる

---

[TCPの3ウェイハンドシェイク](/blog/tcp-three-way-handshake-state-transition-retransmission-congestion-control-guide)で確立した接続は、一度繋がれば「信頼された一本の管」のように振る舞います。しかし攻撃者がその管に**正しいシーケンス番号のセグメントを1つ割り込ませられたら**——受信側はそれを正規のデータとして受け入れてしまう。これが**TCPセッションハイジャック**であり、偽の RST を撃ち込んで接続を**強制切断**するのが **RSTインジェクション**です。

この記事は、[ネットワークペンテストの全体像](/blog/network-penetration-testing-methodology-attack-defense-guide)に続き、これらの攻撃と**IPスプーフィング**の仕組みを TCP の内部から解き、**RFC 5961・RFC 6528・BCP 38** に準拠した防御を示します。鍵はすべて、[TCP が信頼性をシーケンス番号で作っている](/blog/tcp-three-way-handshake-state-transition-retransmission-congestion-control-guide)という事実にあります。

> **安全地帯の徹底**：本記事の検証は、すべて[隔離ラボ](/blog/ethical-hacking-home-lab-kali-juice-shop-ctf-self-study-roadmap-guide)の**自分が管理するVM間のTCP接続**に対してのみ行います。**第三者の通信に RST を注入したりセッションを奪う行為は、通信の秘密の侵害であり、不正アクセス禁止法・電気通信事業法に違反**します。本記事は攻撃の発射手順ではなく**仕組みの理解と防御**に焦点を当てます。[法律の記事](/blog/ethical-hacker-law-japan-unauthorized-access-act-active-cyber-defense-disclosure-guide)を必ず先に。

---

## 1. なぜ TCP 接続に割り込めるのか — シーケンス番号という鍵

TCP は、受け取ったセグメントが「この接続の、正しい位置のデータか」を**シーケンス番号**だけで判断します（[TCP の再送・順序制御の核](/blog/tcp-three-way-handshake-state-transition-retransmission-congestion-control-guide)）。裏を返せば——**5タプル（送信元/宛先IP・ポート・プロトコル）が合致し、シーケンス番号が受信ウィンドウの範囲内**なら、そのセグメントは受理されます。送信者の「本人性」は検証されません。

```text
受信側が1つのセグメントを受理する条件：
  ① 5タプルが既存接続に一致（src/dst IP・src/dst port）
  ② シーケンス番号が「受信ウィンドウ」の範囲内
  → 満たせば、誰が送ったかに関わらずデータとして受理してしまう
```

攻撃は2種類に分かれます。

- **経路上（on-path / MITM 済み）**：[ARPスプーフィング](/blog/arp-spoofing-mitm-attack-detection-defense-guide)等で経路を奪っていれば、シーケンス番号は**観測できる**。割り込みは容易。
- **経路外（off-path / blind）**：番号が見えないので**推測**が必要。当てるべき空間は「ウィンドウサイズ」次第で、大きなウィンドウほど当たりやすい——これが脅威でした。

---

## 2. 3つの攻撃の形

### 2.1 セッションハイジャック — 接続を「乗っ取る」

攻撃者が正しいシーケンス番号で**データセグメント**を注入すると、受信側はそれを正規データとして処理します。認証済みのセッション（例：ログイン後のTCP接続）に悪意あるコマンドを差し込めれば、認証を経ずに操作を乗っ取れます。注入後は本来の送信者と番号がずれて接続が壊れる（ACKストーム）ため、攻撃者は元の送信者を黙らせる必要があります。

### 2.2 RSTインジェクション — 接続を「切る」

[RST フラグ](/blog/tcp-three-way-handshake-state-transition-retransmission-congestion-control-guide)を立てた偽セグメントを、ウィンドウ内のシーケンス番号で送ると、受信側は接続を**即座に破棄**します（`ECONNRESET`）。これは検閲・通信妨害（特定サイトへの接続を片端から切る）に悪用された歴史があります。**1つの偽RSTで、確立済みの接続が落ちる**——その手軽さゆえに危険でした。

### 2.3 IPスプーフィング — 送信元を「偽る」

送信元IPを詐称します。単独では、TCP は[3ウェイハンドシェイク](/blog/tcp-three-way-handshake-state-transition-retransmission-congestion-control-guide)で SYN/ACK が**詐称した本物のIP**へ返ってしまうため、攻撃者は ISN を受け取れず接続を完遂できません（これが歯止め）。しかし——

- **盲目的攻撃**：ISN を推測できれば完遂しうる（→ RFC 6528 で封じる）。
- **DDoS の反射・増幅**：応答が要らないUDP（DNS/NTP等）で送信元を被害者に偽れば、応答を被害者に集中させられる（→ BCP 38 で封じる）。
- **信頼ベース認可の回避**：「このIPからは許可」という弱い認可を破る。

---

## 3. 防御①：番号を推測させない — RFC 6528（ISN ランダム化）

盲目的攻撃の前提は「シーケンス番号（特に接続開始時の ISN）が推測できる」ことです。[RFC 6528](https://www.rfc-editor.org/rfc/rfc6528)（Defending against Sequence Number Attacks）は、**ISN を暗号ハッシュベースで生成**し、接続ごとに予測不能にすることを規定します。

```text
ISN = M + F(localIP, localPort, remoteIP, remotePort, secretKey)
  M … 単調増加クロック
  F … 暗号ハッシュ（接続4タプル＋秘密鍵）。攻撃者は secretKey を知らないため推測不能
```

現代のOSは既定でこれを実装しています。**つまり盲目的ハイジャックは、まともなスタックではまず成立しません**。「TCP ハイジャックは簡単」というのは古い時代の話で、ISN ランダム化がそれを終わらせました。

---

## 4. 防御②：盲目的 RST/SYN を弾く — RFC 5961（challenge ACK）

それでも「ウィンドウが大きいと、番号が範囲内に入る偽RSTを撃ち込める」余地が残ります。[RFC 5961](https://www.rfc-editor.org/rfc/rfc5961)（Improving TCP's Robustness to Blind In-Window Attacks, 2010）は、これを **challenge ACK** で封じます。

仕組みはこうです。**ウィンドウ内だが完全一致ではない RST を受けても、即座に接続を切らない**。代わりに「本当に切るの？」と確認の ACK（challenge ACK）を相手に返す。正規の相手なら整合する応答を返し、偽装攻撃者は正しい応答を作れないため、接続は維持されます。

```text
RFC 5961 の RST 受信時の判定（概念）：
  受信した RST.seq == 次に期待する受信シーケンス番号 → 正規。接続を閉じる
  受信した RST.seq がウィンドウ内だが不一致         → challenge ACK を返す（即閉じない）
  ウィンドウ外                                      → 黙って破棄
```

さらに RFC 5961 は **ACK スロットリング**を定めます：challenge ACK の乱発（それ自体が増幅に悪用されうる）を防ぐため、**一定窓あたりの challenge ACK 数に上限**を設けます（例：任意の5秒で最大10）。

> **設計者の含意**：これらはOSのTCPスタックが担う防御で、アプリ開発者が直接書くものではありません。だからこそ**OS/カーネルを最新に保つ**ことが、ネットワーク層防御の土台になります。古いカーネルは RFC 5961 未実装かもしれません。

---

## 5. 防御③：詐称送信元を経路で落とす — BCP 38（RFC 2827）

IPスプーフィング（特にDDoS反射増幅）への根本対策は、**ネットワークの入口で詐称パケットを落とす**ことです。[BCP 38 / RFC 2827](https://www.rfc-editor.org/rfc/rfc2827)（Network Ingress Filtering）は、ISP・組織が「**そのネットワークから出るはずのない送信元IPのパケットを破棄する**」ことを定めます。

```text
ingress filtering の原則：
  顧客網 10.1.0.0/16 から出ていくパケットの送信元が 10.1.x.x でなければ破棄。
  → 攻撃者は「被害者のIP」を送信元に詐称したパケットを送り出せなくなる。
```

クラウドでは多くがこれを基盤で実施済みです。AWS の VPC は**ソース/デスティネーションチェック**で、インスタンスが自分のIP以外を送信元にしたパケットを既定でドロップします。Linux でも **Reverse Path Filtering（`rp_filter`）**で、戻り経路の整合しないパケットを落とせます。

```bash
# Linux: 受信パケットの送信元が「その経路から来るはずか」を検証（詐称を落とす）
sysctl net.ipv4.conf.all.rp_filter      # = 1 で厳格モード（環境により 2=loose）
```

---

## 6. 最終防壁：TLS — 「番号を奪われても中身は守る」

ここまでの防御（ISN ランダム化・challenge ACK・ingress filtering）はネットワーク層の話です。しかし最も確実なのは——**アプリ層で TLS を使うこと**です。

TLS は接続の上に**暗号化・完全性・認証**を載せます。仮に攻撃者がTCPセグメントを注入できたとしても：

- 注入したデータは TLS の MAC（メッセージ認証）検証に失敗し、**改ざんとして検知**される。
- 中身は暗号化されており、**観測しても読めない**。
- なりすましは証明書検証で**拒否**される。

つまり、**正しく検証された TLS の下では、TCP セッションハイジャックは実害を持ちません**。RST による「切断」は依然ありえますが、それは可用性の問題であり、機密性・完全性は守られます（そして RST は RFC 5961 で困難化されている）。

```ts
import tls from "node:tls";

// アプリの通信は TLS で包む。TCP セグメント注入は MAC 検証で弾かれ「改ざん」として表面化する
const socket = tls.connect(
  { host: "api.example.com", port: 443, servername: "api.example.com" },
  () => {
    // authorized が false なら検証失敗。安全側（使わない）に倒す
    if (!socket.authorized) {
      socket.destroy(new Error(`TLS not authorized: ${socket.authorizationError}`));
      return;
    }
    socket.write("GET / HTTP/1.1\r\nHost: api.example.com\r\nConnection: close\r\n\r\n");
  },
);
socket.on("error", (e) => console.error("tls error:", e.message));
```

---

## 7. まとめ

- **TCP は5タプル＋シーケンス番号で受理を決め、送信者の本人性を検証しない**。だから番号さえ合えば割り込める。
- **3つの攻撃**：セッションハイジャック（乗っ取り）・RSTインジェクション（切断）・IPスプーフィング（送信元詐称）。
- **防御① RFC 6528**：ISN を暗号的にランダム化し、盲目的番号推測を封じる（現代スタックの既定）。
- **防御② RFC 5961**：challenge ACK ＋ ACK スロットリングで盲目的 RST/SYN 注入を困難化。**OS/カーネルを最新に**。
- **防御③ BCP 38**：ingress filtering / rp_filter で詐称送信元を経路で破棄。DDoS 反射増幅を断つ。
- **最終防壁は TLS**：番号を奪われても暗号化・完全性・認証で中身は守られる。

次は、ハンドシェイクの半開状態を悪用してリソースを枯渇させる**[SYNフラッド/DDoS](/blog/syn-flood-ddos-attack-defense-syn-cookies-guide)**を、防御中心に扱います。

---

私（友田 陽大）は、本番システムの TLS/mTLS 化、カーネル/OS のセキュリティ更新運用、AWS VPC のスプーフィング対策（ソース/デスティネーションチェック・最小権限）まで含む“接続を信頼しきらない”設計を実装してきました。「平文の内部通信が残っていないか」「古いカーネルの TCP 脆弱性が不安」「セッションの完全性を担保したい」——こうした接続層の堅牢化を、攻撃者の視点で診断し、暗号化と最新化の両輪で根治します。お気軽にご相談ください。
