実体験:CPU使用率わずか10%でサーバーの接続がダウンした話
ある大規模イベントのチケット発売初日のこと、Webサイトが突如応答しなくなりました。急いでGrafanaを確認したところ、CPU使用率はわずか10〜12%程度で、メモリも32GB中24GB以上空いていました。Nginxはダウンしておらず、データベースも余裕がある状態です。それにもかかわらず、ユーザーからのリクエストは読み込み中のままタイムアウトを返していました。ターミナルを開いてdmesg -Tを実行すると、ログが激しく出力され続けていました。
TCP: Possible SYN flooding on port 443. Sending cookies. Check SNMP counters.
netstat -n -p | grep SYN_RECV | wc -lでネットワークの状態を確認してみると、1,000個を超えるソケットが宙に浮いた(保留)状態になっていました。この時点で、カーネルは新たなハンドシェイクの受付を密かに拒否していたのです。
多くのスタートアップのインフラを監査してきた中で、このパターンは幾度となく目にしてきました。UbuntuやDebianサーバーを構築し、Nginxをインストールして、UFWファイアウォールでポート80と443を開放して完了としてしまうケースです。しかし、LinuxカーネルのデフォルトのTCP/IPパラメータは数十年前のLAN環境を前提に設計されたものであり、ボットネットによる猛烈なスキャンや攻撃に耐えられるようには設定されていないという点が見落とされがちです。
なぜデフォルト設定は簡単にダウンしてしまうのか?
TCPの3ウェイハンドシェイク(3-way handshake)において、クライアントがSYNパケットを送信すると、カーネルはその保留状態(ハーフオープン接続)をSYN Backlogと呼ばれるバッファに保持します。攻撃者はこの仕様を悪用し、送信元IPアドレスを偽装(IPスプーフィング)した何万ものSYNパケットを毎秒送りつけ、最後のACKパケットを決して返さずに立ち去ります。
その結果、主に以下の3つのボトルネックが発生します。
- SYNキューの枯渇(オーバーフロー): 多くのディストリビューションにおける
tcp_max_syn_backlogのデフォルト値は128〜1024程度にすぎません。ボットネットが数秒パケットを送り続けるだけでこのバッファは満杯になり、カーネルは正規ユーザーからの接続も自動的にドロップしてしまいます。 - 偽装パケットの通過: デフォルトでは、Linuxは着信パケットが受信インターフェース経由で逆方向にルーティング可能かどうかを検証しないことがよくあります。このルーティング上の隙により、サーバーは容易にIPスプーフィング攻撃の標的となってしまいます。
- コネクショントラッキングテーブルの枯渇: Netfilter(iptables/UFWの基盤)は、
nf_conntrackテーブルを介して各パケットのステートを管理する必要があります。数百万もの架空接続が押し寄せると、このテーブルの上限値nf_conntrack_maxに達してしまい、ネットワーク層で大規模なパケットロスが発生します。
一般的な防御ソリューションの比較
DoSによるネットワークの輻輳に対処する場合、一般的には3つのアプローチが考えられます。
- CDN / WAF(Cloudflare、Fastlyなど)の導入: HTTP/HTTPSのWeb層には非常に有効です。ただし、攻撃者にオリジンIPが露呈している場合や、TCPマイクロサービス、データベースなどのポートを直接保護する必要がある場合には効果を発揮しません。
- iptables / nftablesによるレート制限ルールの設定: 既知のスパムIPをフィルタリングするのに適しています。しかし、トラフィックが急増した際、すべてのパケットに対して無数のルールを照合し続けると、膨大なCPUリソースを消費してしまいます。
- sysctlによるカーネルパラメータの最適化: 最もコストパフォーマンスが高く効果的な第1防衛ラインです。カーネル層で直接調整を行うことで、不要なパケットがアプリケーションのリソースを消費する前に、わずか数ナノ秒でドロップできます。
sysctlを使ったLinuxカーネル堅牢化の実践手順
Linuxのネットワーク設定フラグは、仮想ファイルシステム/proc/sys/内に配置されています。これらはsysctlコマンドを使用して安全かつ直接設定変更が可能です。
1. SYN CookiesによるSYN Flood攻撃の徹底防御
通常、カーネルはハーフオープン接続ごとにメモリ(RAM)を割り当てます。しかし、SYN Cookiesを有効にすると、カーネルはRAMにステートを保存しなくなります。その代わりに、接続情報を数学的な暗号化シークエンス番号としてクライアントへ返送するパケット内に埋め込みます。
この値を含む正当なACKパケットを受信して初めて、サーバーは実際のリソースを割り当てます。これにより、SYNキューが完全に満杯になって膠着するのを防ぐことができます。
# SYNキューが満杯になった際にSYN Cookiesを有効化
net.ipv4.tcp_syncookies = 1
# SYN backlogキューのサイズをデフォルトから8,192接続へ拡張
net.ipv4.tcp_max_syn_backlog = 8192
# SYN-ACKパケットの再試行回数を5回から2回に減らし、不要なソケットを約9秒で解放
net.ipv4.tcp_synack_retries = 2
2. Reverse Path FilteringによるIPスプーフィングの遮断
Reverse Path Filtering(rp_filter)の仕組みにより、カーネルはパケットの送信元IPアドレスをルーティングテーブルと照合することを強制されます。もしパケットがeth0から届いたにもかかわらず、正当な戻りルートが別のインターフェースにある、またはルーティング不能である場合、カーネルはそのパケットを即座に破棄します。
# 値「1」でStrict Mode(厳格モード)を有効化(主要なネットワークインターフェースが1つのスタンドアロンサーバーに推奨)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
3. ICMP Redirectの無効化とSmurf攻撃の防止
ICMPはネットワーク診断用のプロトコルですが、ルーティングテーブルの汚染(ICMP Redirect)や、DoS攻撃の増幅踏み台(Smurf攻撃)として攻撃者に悪用されることがよくあります。サーバーがルーターとして動作していない場合は、これらの機能を完全に無効化してください。
# 外部からのICMPリダイレクトパケットの受信を拒否
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
# 他のホストへのICMPリダイレクト通知の送信を無効化
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# ブロードキャストアドレス宛てのすべてのICMP echoリクエストを無視
net.ipv4.icmp_echo_ignore_broadcasts = 1
# ICMPエラーメッセージの送信レートを制限(最小間隔100ms)
net.ipv4.icmp_ratelimit = 100
4. ハングしたソケットの回収とコネクショントラッキングテーブルの拡張
ポートスキャンやDoS攻撃を受けると、サーバー上にTIME_WAITやFIN_WAIT_2状態で滞留する大量のソケットが残存しがちです。これによりエフェメラルポート(一時ポート)が枯渇してしまいます。そのため、これら不要な接続の保持時間を短縮します。
# ソケットの終了待ち時間を60秒から15秒に短縮
net.ipv4.tcp_fin_timeout = 15
# 安全な新規接続のためにTIME-WAIT状態のソケットの再利用を許可
net.ipv4.tcp_tw_reuse = 1
# netfilterの状態追跡テーブルを100万件以上に拡張(1レコードあたり約300バイトのメモリを消費)
net.netfilter.nf_conntrack_max = 1048576
# ソケットのlistenバックログの上限を65,535に引き上げ
net.core.somaxconn = 65535
本番環境への安全な適用手順
デフォルトの/etc/sysctl.confファイルを直接編集することは避けてください。OSのアップグレード時に上書きされるリスクがあります。代わりに、設定を分離して/etc/sysctl.d/ディレクトリ配下に配置します。
ステップ1:新しい設定ファイルを作成します。
sudo nano /etc/sysctl.d/99-security-hardening.conf
ステップ2:厳選したパラメータをファイルに保存します。
# 1. IPスプーフィング対策(厳格なReverse Path Filtering)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# 2. SYN Flood攻撃対策
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_synack_retries = 2
# 3. ICMP悪用およびソースルーティングの防止
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# 4. ネットワーク接続回収の最適化
net.core.somaxconn = 65535
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
ステップ3:サーバーを再起動せずに変更を即座に反映します。
sudo sysctl --system
ステップ4:新しい設定値がカーネルに反映されたか確認します。
sysctl net.ipv4.tcp_syncookies net.ipv4.conf.all.rp_filter
出力に= 1と表示されれば、設定は正常に適用されています。わずか数分のチューニングで、カーネル層に堅牢なシールドを構築でき、追加のハードウェアコストをかけることなく自動化されたボットネットのスキャンや攻撃からサーバーを守り抜くことができます。

