TCPの3ウェイハンドシェイクは「SYN → SYN/ACK → ACK」の3手で接続を確立します。では、攻撃者が最初の SYN だけ送って、最後の ACK を永遠に返さなかったらどうなるでしょうか。サーバーは「相手の ACK を待つ未完成の接続(半開状態)」を抱えたまま、リソースを握り続けます。これを大量に仕掛けて接続キューを埋め尽くし、正規ユーザーが繋げなくするのが SYNフラッド——古典にして今なお有効な DoS(サービス妨害)攻撃です。
この記事は、ネットワークペンテストの全体像に続き、SYNフラッドと DDoS を RFC 4987(TCP SYN Flooding Attacks and Common Mitigations)に忠実に、防御中心で解説します。
本記事の方針 — 攻撃手順は扱いません DoS/DDoS は他者のサービスを妨害する攻撃であり、日本では電子計算機損壊等業務妨害罪等に問われうる明確な違法行為です。本記事は防御側の知識として、「なぜリソースが枯渇するのか」「どう緩和するのか」だけを扱い、攻撃ツールや負荷生成のコマンドは一切示しません。自分のサーバーの耐性試験を行う場合も、必ず隔離ラボか、書面で合意した負荷試験(公式の負荷試験サービス)の枠内で行ってください。
1. なぜ半開接続でリソースが枯渇するのか
サーバーが SYN を受け取ると、SYN-RECEIVED 状態に遷移し、最後の ACK を待つ間、その接続の情報を SYN バックログ(キュー)に保持します(TCP の状態遷移参照)。
正常な接続:
client ── SYN ──► server (SYN-RECEIVED:バックログに1枠確保し ACK を待つ)
client ◄ SYN/ACK ─ server
client ── ACK ──► server (ESTABLISHED:バックログの枠を解放)
SYNフラッド:
attacker ── SYN ──► server (SYN-RECEIVED:枠を確保)
attacker ◄ SYN/ACK ─ server
attacker ……(ACK を返さない)…… ← 枠が解放されないまま放置
これを大量に繰り返す → バックログが半開接続で満杯 → 正規の SYN を受け付けられない
RFC 4987 が説明する核心は、**「バックログという有限のリソースを、未完成の接続で占有させる」**ことです。攻撃者は接続を完成させる気がないので、自分のリソースはほとんど消費しません。しかも送信元IPを詐称(IPスプーフィング)すれば、SYN/ACK は無関係な第三者へ飛び、攻撃者の追跡も難しくなります。**非対称(攻撃者は軽く、被害者は重い)**であることが、この攻撃の厄介さです。
2. 防御の本命:SYN cookies(RFC 4987)
RFC 4987 が挙げる緩和策の中心が SYN cookies です。発想が見事で——SYN を受けた時点では状態を一切保存しない。
2.1 仕組み
通常:SYN 受信 → バックログに状態を保存 → ACK を待つ(ここが枯渇する)
SYN cookies:
SYN 受信 → 状態を保存しない!
代わりに「接続情報+時刻+秘密鍵」を暗号的に符号化した値を
初期シーケンス番号(ISN)として SYN/ACK で送り返す(= cookie)
ACK 受信 → ACK 番号 = cookie+1 から、接続情報を復元・検証
正しければ、その時点で初めて接続を構築(ESTABLISHED)
最後の ACK が来なければ何も起きない——バックログを消費しないので、フラッドで枯渇しない。これが SYN cookies の威力です。
2.2 既定では「常時オン」ではない
RFC 4987 が注記する通り、SYN cookies は TCP オプション(ウィンドウスケール・SACK 等)の一部を完全には保持できないトレードオフがあるため、多くのOSで**「高負荷時(バックログ逼迫時)だけ自動的に発動」**する設計です。常時オンにはしません。
# Linux: SYN cookies を有効化(高負荷時に自動発動する“安全弁”)
sysctl net.ipv4.tcp_syncookies # = 1 が推奨(多くのディストリで既定)
# 併せてバックログ関連を環境に応じて調整(むやみに巨大化しない)
sysctl net.ipv4.tcp_max_syn_backlog # 未完成接続キューの上限
sysctl net.core.somaxconn # accept 待ちキューの上限(アプリの listen backlog と整合させる)
3. 多層防御 — サーバー単体で守りきらない
SYN cookies は強力ですが、現代の DDoS は体積(ボリューム)型が主流で、回線そのものを溢れさせます。これはサーバー1台では守れません。多層で考えます。
3.1 ホスト/カーネル層
- SYN cookies 有効化(§2)。
tcp_synack_retriesを抑える:半開接続が SYN/ACK を再送し続ける時間を短縮し、枯渇を早く解消。- 過大なバックログ拡大は根治ではない(攻撃量が上回れば同じ)。安全弁は SYN cookies。
3.2 ネットワーク/エッジ層
- SYN プロキシ:ファイアウォール/ロードバランサが握手を肩代わりし、3ウェイが完成した接続だけをバックエンドへ渡す。バックエンドは半開接続を一切見ない。
- レート制限:送信元あたりの新規接続レートに上限。
- BCP 38(ingress filtering):送信元詐称を経路で落とし、反射増幅型を抑える。
3.3 上流/クラウド層(体積型 DDoS の本命)
体積型は自分の回線に届く前に吸収するしかありません。
- クラウド DDoS 防御:AWS Shield(Standard は L3/L4 を自動緩和)、Cloudflare、Google Cloud Armor。
- Anycast + スクラビング:トラフィックを地理分散し、巨大なキャパシティで吸収・洗浄する。
- WAF:L7(HTTP フラッド)に対しては、レート制限ルール・BotID/CAPTCHA で正規/悪性を分離。
設計の含意:DDoS 耐性は「アプリのコード」ではなく「アーキテクチャ」で決まります。インターネットに直接サーバーを晒さず、CDN/WAF/クラウド DDoS 防御の背後に置くことを設計段階の前提にします。これは私が AWS で本番システムを構築する際の基本姿勢です。
4. 検知 — 「半開接続の異常な増加」を可視化する
防御が効いているかを知るには、半開接続とSYNレートを観測します。
# SYN-RECV(半開)状態の接続数を数える。平常時から跳ね上がっていれば SYN フラッドの兆候
ss -tan state syn-recv | wc -l
# 状態ごとの分布を俯瞰(SYN-RECV が支配的なら異常)
ss -tan | awk 'NR>1{print $1}' | sort | uniq -c | sort -rn
4.1 観測値から判定する純粋関数(型安全)
メトリクス(半開接続数・新規SYNレート)から「SYNフラッドらしさ」を判定するロジックを、副作用なしで書きます。アラートや自動緩和(SYN cookies はカーネルが自動発動するので、ここでは通知・上流防御の起動判断に使う)につなげられます。
/** ある観測時点のTCP接続メトリクス。 */
interface TcpHealthSample {
readonly synRecvCount: number; // SYN-RECV(半開)の数
readonly establishedCount: number; // ESTABLISHED の数
readonly newSynPerSec: number; // 新規SYN到着レート
}
interface FloodVerdict {
readonly isLikelyFlood: boolean;
readonly halfOpenRatio: number;
readonly reason: string;
}
/**
* 半開接続の比率と SYN レートから SYN フラッドの兆候を判定する純粋関数。
* 「半開が確立済みに対して異常に多い」かつ「新規SYNレートが平常の閾値超」を兆候とする。
* 副作用なし=テスト容易・誤検知は閾値調整で安全に対応(正常なスパイクを誤報しない)。
*/
export function detectSynFlood(
sample: TcpHealthSample,
baselineSynPerSec: number,
halfOpenRatioThreshold = 2, // 半開 ÷ 確立 がこれを超えたら疑う
synRateMultiplier = 5, // 平常比 ×5 のSYNレートを疑う
): FloodVerdict {
const established = Math.max(sample.establishedCount, 1); // 0除算回避
const halfOpenRatio = sample.synRecvCount / established;
const ratioHot = halfOpenRatio >= halfOpenRatioThreshold;
const rateHot = sample.newSynPerSec >= baselineSynPerSec * synRateMultiplier;
return {
isLikelyFlood: ratioHot && rateHot,
halfOpenRatio,
reason: `halfOpenRatio=${halfOpenRatio.toFixed(2)} (hot=${ratioHot}), synRate=${sample.newSynPerSec} (hot=${rateHot})`,
};
}
2条件のAND(半開比率 & SYNレート)にすることで、正規のトラフィックスパイク(半開比率は上がらない)を誤検知しにくくしています。誤報の少ない検知は、運用の信頼を保つうえで重要です。
5. まとめ
- SYNフラッドは半開接続でバックログを枯渇させる非対称攻撃。攻撃者は軽く、被害者は重い。送信元詐称を伴うことが多い。
- 本記事は攻撃手順を扱わず防御に徹する——DoS は違法。守る知識として原理と緩和を押さえる。
- 本命は SYN cookies(RFC 4987):SYN 受信時に状態を保存せず、暗号符号化した ISN で握手を完成させる。バックログを消費しない。高負荷時のみ自動発動が定石。
- 多層で守る:カーネル(SYN cookies・retries 抑制)→ エッジ(SYN プロキシ・レート制限・BCP 38)→ 上流(クラウド DDoS 防御・Anycast・WAF)。
- 体積型 DDoS はアーキテクチャで守る:サーバーを直接晒さず、CDN/WAF/クラウド防御の背後に置くのを設計前提にする。
- 検知:半開接続比率と SYN レートを観測し、AND 条件で誤報を抑えて可視化する。
次は、MITM の成果を「読む」フェーズ——**パケット盗聴 / Wireshark / 暗号化による防御**を扱い、クラスタを締めます。
私(友田 陽大)は、AWS 上で WAF・Shield・CDN を前提とした DDoS 耐性のあるアーキテクチャ設計、SYN cookies やレート制限を含むカーネル/エッジのチューニング、半開接続やトラフィック異常の可観測性を実装してきました。「DDoS に耐えられる構成にしたい」「サーバーを直接インターネットに晒していて不安」「トラフィック異常を検知したい」——こうした可用性の堅牢化を、攻撃者の視点で診断し、多層防御と可観測性で根治します。お気軽にご相談ください。