メインコンテンツへスキップ
友田 陽大
実践ネットワーク攻撃と防御
セキュリティ
ネットワーク
TCP/IP
TCP
脆弱性診断
ホワイトハッカー

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 による無害化まで型安全なコードで示します。すべて隔離ラボに閉じた合法手順です。

公開日
読了時間
9分
著者
友田 陽大
シェア

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

この記事は、ネットワークペンテストの全体像に続き、これらの攻撃とIPスプーフィングの仕組みを TCP の内部から解き、RFC 5961・RFC 6528・BCP 38 に準拠した防御を示します。鍵はすべて、TCP が信頼性をシーケンス番号で作っているという事実にあります。

安全地帯の徹底:本記事の検証は、すべて隔離ラボ自分が管理するVM間のTCP接続に対してのみ行います。第三者の通信に RST を注入したりセッションを奪う行為は、通信の秘密の侵害であり、不正アクセス禁止法・電気通信事業法に違反します。本記事は攻撃の発射手順ではなく仕組みの理解と防御に焦点を当てます。法律の記事を必ず先に。


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

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

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

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

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

2. 3つの攻撃の形

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

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

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

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

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

送信元IPを詐称します。単独では、TCP は3ウェイハンドシェイクで SYN/ACK が詐称した本物のIPへ返ってしまうため、攻撃者は ISN を受け取れず接続を完遂できません(これが歯止め)。しかし——

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

3. 防御①:番号を推測させない — RFC 6528(ISN ランダム化)

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

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(Improving TCP's Robustness to Blind In-Window Attacks, 2010)は、これを challenge ACK で封じます。

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

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(Network Ingress Filtering)は、ISP・組織が「そのネットワークから出るはずのない送信元IPのパケットを破棄する」ことを定めます。

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

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

# 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 で困難化されている)。

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**を、防御中心に扱います。


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

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この攻撃、あなたのネットワークで成立しませんか?

ネットワーク/インフラのペネトレーションテスト・堅牢化を承ります

この記事で扱った ARPスプーフィング・DNS汚染・セッションハイジャック・SYNフラッド・盗聴といった L2〜L4 の攻撃を、御社の構成で『どこが破れるか』を攻撃者の視点で診断し、RFC準拠の防御(DAI・DNSSEC・RFC 5961・BCP 38・TLS/mTLS・WAF/DDoS防御)まで設計・実装します。AWS マルチアカウントで多層ネットワーク(VPC・最小権限IAM・GuardDuty・WAF)を構築してきた知見で、攻撃面の最小化とゼロトラスト化を伴走します。

プロジェクト単位(請負)・技術顧問のどちらにも対応可能です。まずは30分の無料技術相談から。

あわせて読みたい