パケットフィルタリング型ファイアウォールは、通信の状態を参照しないステートレス方式と、参照するステートフル方式に大別できます。国内の解説ではステートフル側をさらに分け、「静的(ステートレス)」「動的(ダイナミック)」「ステートフルインスペクション(SPI)」の3方式で説明することもあります。違いがはっきり出るのは、内側から始めた通信の戻りパケットをどう通すかです。この記事では3方式の判定の仕組みを比べ、Linuxのconntrack(netfilterの接続追跡)の既定値、nftablesのルール、AWSのセキュリティグループとネットワークACLを例に、設定の何が変わるのかまで説明します。
まとめ:3方式の違いと選び方の要点
- 静的パケットフィルタリングはパケットを1つずつ独立に判定します。戻り通信を通すには、エフェメラルポート(クライアント側が一時的に使うポート)の広い範囲を常時開けておく必要があります。
- 動的パケットフィルタリングは、内側から出た通信を接続表に記録し、その戻りだけを通す穴をその都度開けます。
- ステートフルインスペクションは、接続表に加えてTCPの状態遷移やシーケンス番号の整合まで確かめ、つじつまの合わないパケットを捨てます。
- Linuxのconntrackやクラウドのセキュリティグループは、動的とステートフルの機能を1つの仕組みで実現しています。製品の説明では両者をまとめて「ステートフル」と呼ぶのが普通です。
- どの方式もSQLインジェクションのようなアプリケーション層の攻撃は止められないため、WAFやIPSと組み合わせます。
| 方式 | 判定に使う情報 | 戻り通信 | 代表的な実装 |
|---|---|---|---|
| 静的(ステートレス) | ヘッダのみ | ルールで常時許可 | AWSネットワークACL |
| 動的 | ヘッダ+接続表 | 接続ごとに自動許可 | 古いルーターの動的ACL |
| ステートフルインスペクション | ヘッダ+接続表+TCP状態 | 状態が整合すれば許可 | conntrack、セキュリティグループ |
パケットフィルタリングの判定:ヘッダの5項目とルールの照合順
基本となるステートレスのパケットフィルタリングは、IPヘッダとTCP/UDPヘッダに書かれた情報だけで通すか捨てるかを決めます(ステートフル方式はこれに接続の状態を加えます)。照合に使うのは主に、送信元IPアドレス、宛先IPアドレス、プロトコル番号(TCP=6、UDP=17、ICMP=1)、送信元ポート、宛先ポートの5項目です。この組をまとめて5タプルと呼びます。TCPではSYNやACKといったフラグも条件に使えます。
ルールの並びはACL(アクセス制御リスト)と呼ばれ、多くの実装では上から順に照合して最初に一致したルールで処理が決まります。どれにも一致しなければ既定の動作(多くは拒否)になります。AWSのネットワークACLもルール番号の小さい順に評価し、一致した時点で残りを見ません。広い許可より先に個別の拒否を書く、という順序の設計がそのまま効いてきます。ヘッダの各項目がどの層の情報かはTCP/IPとは?4階層モデルとOSI参照モデルの違いを実装目線で解説で整理しています。
静的(ステートレス)フィルタリングで戻り通信に必要なルール
静的フィルタリングの弱点は、社内PCが外部のWebサイトへHTTPSで接続する場面を考えるとわかります。行きのパケットは「宛先ポート443」で許可できます。しかし戻りのパケットは送信元ポートが443、宛先ポートがPC側のエフェメラルポートになり、このポート番号は接続のたびに変わります。過去の通信を覚えていない静的フィルタでは、エフェメラルポートの範囲全体を「外から入ってきてよい」と常時開けておくしかありません。
この範囲はOSによって違います。Linuxカーネルの既定は32768〜60999(ip_local_port_range)で、Windows Server 2008以降は49152〜65535です。AWSのドキュメントは、相手のOSが混在する公開サーバー向けに「1024〜65535を開けてもよいが、その範囲内の危険なポートには、広い許可より前に拒否ルールを置く」と案内しています。
| クライアントの種類 | エフェメラルポート範囲 |
|---|---|
| Linuxカーネル既定 | 32768〜60999 |
| Windows Server 2008以降 | 49152〜65535 |
| AWS NATゲートウェイ | 1024〜65535 |
| Elastic Load Balancing | 1024〜65535 |
| AWS Lambda | 1024〜65535 |
開けた範囲には、戻り通信に限らず、送信元ポートを443に偽装した外部からのパケットも入ってきます。TCPの「ACKフラグが立っているパケットだけ通す」という条件を足すと、外部からの新規接続(SYNだけのパケット)は弾けます。ただし、ACKを付けて偽装したパケットや、そもそもフラグのないUDPは防げません。「ステートフルインスペクション機能をもたない静的なパケットフィルタリング型」の機器を社内ネットワークとインターネットの接続点に置く構成では、この戻り通信用の常時開放が設計の前提になります。
動的パケットフィルタリング:接続表で戻り通信の穴を開け閉めする仕組み
動的パケットフィルタリングは、内側から外へ出たパケットの5タプルを接続表(コネクションテーブル、セッションテーブル)に記録します。戻ってきたパケットの送信元と宛先を入れ替えた組が表にあれば通し、無ければ捨てます。エフェメラルポートを常時開けておく必要がなくなり、穴は「その接続の、その相手からの戻り」だけに絞られます。
接続表のエントリが消えるタイミング:Linux conntrackの既定値
接続表の各エントリには寿命があります。TCPならFINやRSTで接続が終われば短い待ち時間のあとに消え、通信が止まったまま放置されたエントリはタイムアウトで消えます。Linuxのconntrackの既定値は次のとおりです(カーネル文書nf_conntrack-sysctl)。
| sysctl | 既定値 | 対象 |
|---|---|---|
| nf_conntrack_tcp_timeout_established | 432000秒(5日) | 確立済みTCP |
| nf_conntrack_tcp_timeout_syn_sent | 120秒 | SYN送信後の応答待ち |
| nf_conntrack_tcp_timeout_time_wait | 120秒 | TIME_WAIT |
| nf_conntrack_udp_timeout | 30秒 | UDP(通常) |
| nf_conntrack_udp_timeout_stream | 120秒 | UDP(ストリーム判定時) |
| nf_conntrack_icmp_timeout | 30秒 | ICMP |
確立済みTCPの5日はかなり長い値で、途中の機器はもっと短く切ることがあります。たとえばAWSのNATゲートウェイは、350秒以上無通信の接続をタイムアウトさせます。ファイアウォールやNAT越しの長時間接続(DB接続プールやSSH)が無通信のあと突然切れるときは、途中機器の接続表タイムアウトを疑い、TCPキープアライブの間隔をそれより短くします(AWSもNATゲートウェイについて350秒未満のキープアライブを案内しています)。
UDPとICMPを「接続」として扱う方法
UDPにはTCPのような接続確立の手順がありません。そのため接続表は、同じ5タプルのパケットが一定時間内に往復したことを根拠に、擬似的な接続として扱います。Linuxのconntrackは、UDPのエントリを通常30秒で消します。応答が返ってきたうえで、最初のパケットから2秒を過ぎてもやり取りが続いている場合だけ、ストリームとみなして120秒に延ばします(nf_conntrack_proto_udp.c)。DNSの問い合わせのように1往復ですぐ終わる通信は、30秒のまま消えます。ICMPのエコー要求(ping)も、識別子を手がかりに応答と対応付けます。
ステートフルインスペクション:TCPの状態とシーケンス番号の整合検査
ステートフルインスペクションは、動的フィルタリングの接続表に「その接続がいまどの段階にあるか」という状態を加えます。TCPなら、SYN送信・SYN/ACK受信・確立済み・終了処理中といった遷移を追い、その段階でありえないパケットを不正とみなします。
動的フィルタリングとの差:つじつまの合わないパケットの判定
5タプルが一致するだけなら、攻撃者が通信中の組を推測して偽のパケットを差し込む余地が残ります。ステートフルインスペクションでは、次のようなパケットが不正と判定され、拒否の対象になります。
- SYNを送っていないのに届いたSYN/ACK
- 確立前の接続に届いたデータ付きパケット
- 受信ウィンドウの範囲から外れたシーケンス番号を持つパケット
Linuxのconntrackはこの判定をしています。nf_conntrack_tcp_be_liberalの既定は0で、この設定のときはウィンドウ外のパケットをINVALID(不正)として印を付けます。1にするとウィンドウ外のRSTだけを不正扱いし、それ以外は見逃します。非対称ルーティングなどで正規の通信まで不正扱いされるときに、回避策として有効にされることがあります。
ただし、conntrackが行うのは判定と印付けまでです。INVALIDのパケットを実際に捨てるかどうかは、ルールにct state invalid dropを書くかで決まります。またnf_conntrack_tcp_looseの既定は有効(1)で、3ウェイハンドシェイクを見ていない途中からの接続も追跡を始めます。どこまで厳しく判定するかは、実装と設定で変わります。
FTP関連通信の許可:ヘルパーによる制御接続の解析
FTPのアクティブモードでは、制御用の接続(21番)の中でデータ用接続のポート番号をやり取りし、サーバー側から新しい接続を張ってきます。5タプルの照合だけではこの新しい接続を「関連する戻り」と判断できません。そこでステートフルインスペクションの実装は、制御接続の中身を読んでポート番号を拾い、その接続を予約として接続表に入れます。Linuxではこれを「ヘルパー」が担い、予約に一致した接続はRELATED状態になります。なお、Linux 4.7(2016年)からはヘルパーの自動割り当てが既定で無効になりました。FTPの関連通信を通したいときは、nftablesのct helperなどでどの通信にヘルパーを使うかを明示します。
ここで読むのは、状態を追うのに必要な部分(FTPのPORTコマンドなど)だけです。HTTPの中身に攻撃文字列が含まれているかどうかは見ません。「ステートフルインスペクションはアプリケーション層まで検査する」という説明を見かけますが、攻撃の検出という意味でアプリケーション層を検査するのはIPSやWAF、次世代ファイアウォールの役割です。
ステートフルインスペクションの起源:Check PointのFireWall-1
状態を覚えるパケットフィルタを製品として広めたのは、イスラエルのCheck Point Software Technologiesです。創業者のGil Shwed氏を発明者とする米国特許5,606,668は1993年12月15日に出願され、1997年2月25日に登録されました。同社が1994年に出した最初の製品FireWall-1が、この技術を基にしています。特許の明細書は、セキュリティルールを中間言語に変換してパケットフィルタの仮想マシンで実行する仕組みが中心です。そのなかに、UDPのようなコネクションレスの通信を「双方向とも何秒パケットが流れなければ終わったとみなすか」というタイムアウトの定義が出てきます。前の章で見たUDPの擬似的な接続は、この時点ですでに設計に入っていました。
「動的」と「ステートフル」の呼び分けが資料ごとに食い違う理由
国内の解説記事には、静的・動的・ステートフルインスペクションの3分類で説明するもの(IT製品比較サイトやIT教育サイトの解説など)があります。一方、AWSのVPCドキュメントやnftablesのwikiは「stateless」と「stateful」の2分類で説明しており、動的という段階を別に立てていません。現在の実装は接続表と状態の検査を一体で持っているので、両者を分ける必要がないからです。
Linuxのconntrackはその典型です。接続表(動的フィルタリングの機能)と、TCPの状態遷移・ウィンドウの検査(ステートフルインスペクションの機能)を同じ仕組みで処理し、結果をNEW・ESTABLISHED・RELATED・INVALIDの状態としてルールに渡します。
3分類で説明する資料では、動的は「戻り通信の穴を自動で開ける」、ステートフルインスペクションは「さらにTCPの状態やシーケンス番号の整合まで見る」と区別しているのが一般的な整理で、本記事もこれに従っています。試験で問われたときは、出題元が示す定義に従ってください。
製品やクラウドの選定では、「stateful」という名称だけで検査の範囲を判断しないでください。公式の仕様で、どの通信を追跡するか、追跡しない通信の条件は何か、不正な状態のパケットをどう扱うかを確認します。たとえばAWSのセキュリティグループでも、送受信とも全アドレス・全ポートを許可しているTCP/UDPの通信は追跡の対象外になります。
nftablesとAWSで見るステートレスとステートフルの設定差
nftablesの受信ルール:ポート範囲指定とct stateの比較
Linuxホスト自身の受信(inputフック)で、「SSHの受け付け」と「自分から始めたHTTPSとUDPのDNSの戻り」を通すルールを書き比べます。送信は制限していない前提で、2つのテーブルは同時に読み込まず別々に試す例です。IPv6の近隣探索とpingを通すため、どちらにもICMP・ICMPv6の許可を入れています。まずはct stateを参照しないステートレス版です(カーネルの接続追跡そのものは動いており、ルールが状態を見ていないだけです)。戻りのためにエフェメラルポートの範囲を開けています。
table inet stateless_demo {
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
meta l4proto { icmp, ipv6-icmp } accept
tcp dport 22 accept
# HTTPS の戻り:送信元443からエフェメラルポート全体を許可
tcp sport 443 tcp dport 32768-60999 accept
# DNS(UDP)の戻り
udp sport 53 udp dport 32768-60999 accept
}
}
同じ要件をct state(nftables wiki)で書いたステートフル版です。戻り通信はすべてestablished,relatedの1行で通り、エフェメラルポートを開けるルールが要りません。
table inet stateful_demo {
chain input {
type filter hook input priority filter; policy drop;
ct state invalid drop
ct state established,related accept
iif "lo" accept
meta l4proto { icmp, ipv6-icmp } accept
tcp dport 22 ct state new accept
}
}
ステートレス版では、送信元ポートを443や53に偽装したパケットが32768〜60999のどのポートにも届きます。ステートフル版でポート22以外に届くのは、接続追跡で既存の接続や関連する接続と判定されたパケットと、明示的に許可したループバック・ICMP・ICMPv6だけです。ct state invalid dropを先頭に置くと、前の章で触れたウィンドウ外のパケットや手順違反のパケットがここで落ちます。iptablesで同じことをする書き方とnftablesへの移行はiptablesとは?Linuxのパケットフィルタとファイアウォール設定・nftablesへの移行を実装目線で解説で扱っています。
AWSのセキュリティグループ(ステートフル)とネットワークACL(ステートレス)
AWSのVPCには、ステートフルなセキュリティグループと、ステートレスなネットワークACLの両方があります。AWSの公式ドキュメントは、ネットワークACLについて「受信を許可しても、その応答は自動では許可されない」、セキュリティグループについて「受信を許可すれば、送信ルールにかかわらず応答は自動で許可される」と説明しています。
| 項目 | セキュリティグループ | ネットワークACL |
|---|---|---|
| 方式 | ステートフル | ステートレス |
| 適用単位 | インスタンス等のリソース | サブネット |
| 戻り通信 | 自動で許可 | ルールが別途必要 |
| 拒否ルール | 書けない(許可のみ) | 書ける |
| 評価順 | 全ルールを集約して判定 | 番号の小さい順 |
ネットワークACLでサブネット内のサーバーから外部へHTTPSを使わせるには、送信側の443番の許可に加えて、受信側にエフェメラルポートの許可が必要です。AWS CLIでは次のように書きます。ACL IDは自分の環境のものに、ルール番号は既存のルールと重ならない番号に置き換えてください。ポート範囲はAWSのドキュメントの例と同じ32768〜65535です。より小さい番号に拒否ルールがあれば、そちらが先に効きます。
aws ec2 create-network-acl-entry \
--network-acl-id acl-0123456789abcdef0 \
--ingress \
--rule-number 140 \
--protocol 6 \
--port-range From=32768,To=65535 \
--cidr-block 0.0.0.0/0 \
--rule-action allow
この戻り通信用の受信ルールを書き忘れると、セキュリティグループが正しくても通信は成立しません。ネットワークACLを絞ったあとに外部への接続がタイムアウトするようになったら、送信ルール(宛先443番の許可)と受信ルール(エフェメラルポートの許可)を両方向とも番号順にたどり、先に一致する拒否ルールがないかを確認します。なお、セキュリティグループのルールを変更しても、追跡中の接続はタイムアウトするまで通り続けます。即座に遮断したいときはネットワークACLを使うよう、AWSは案内しています。AWSでさらにペイロードまで検査したいときの選択肢はAWS Network Firewallとは?仕組み・ルール・料金とセキュリティグループとの違いを実装目線で解説を参照してください。
ステートフルインスペクションで防げない攻撃と運用上の限界
- アプリケーション層の攻撃:正規のTCP接続の中を流れるSQLインジェクションやクロスサイトスクリプティングは、状態としては正常なので素通りします。Webアプリケーションの防御はWAFとは?仕組み・ファイアウォール/IPS・IDSとの違いと企業の選び方を解説の領域です。
- 暗号化された通信の中身:TLSの中身は見えません。マルウェアの通信がHTTPSで外へ出ていく場合、宛先のIPアドレスとポートでしか止められません。
- 接続表の枯渇:SYNフラッドのように大量の偽接続を作られると表が埋まります。Linuxでは上限
nf_conntrack_maxに達すると、カーネルログに「nf_conntrack: table full, dropping packet」が出て、正規の新しい接続まで捨てられます。 - 冗長化での状態の引き継ぎ:接続表は機器のメモリにあるので、冗長構成で待機系に切り替わると、状態を同期していない場合は既存の接続を継続できないことがあります。途中から追跡し直せる実装もありますが、NATの変換情報や適用ルールによって結果が変わります。製品では状態の同期を「ステートフルフェイルオーバー」という別機能として提供しています。
侵入の兆候を見つける仕組みと組み合わせる考え方はIDS・IPSとは?違い・仕組み・種類とファイアウォール/WAFとの使い分けを解説で解説しています。
方式の選び方:ステートレスを残す場面とステートフルが必須の場面
任意の外部サービスへ接続するクライアントやサーバーを守る境界では、主役をステートフルにすべきです。静的フィルタリングでも通信相手のアドレスやポートを絞ることはできます。しかし戻り通信を接続の履歴と照合できないので、相手を限定できない通信では、戻りのために数万ポートを開け続けることになります。
そのうえで、ステートレスを意図して残す場面が2つあります。
- 粗い遮断を前段に置く:AWSでネットワークACLに特定の送信元IPアドレス範囲の拒否を書き、セキュリティグループで細かい許可を書く、という二段構えです。セキュリティグループには拒否ルールが書けないため、この分担になります。
- 接続表を使わないほうが安全な大量通信:権威DNSサーバーのように、1パケットで完結するUDPを大量に受けるサーバーでは、conntrackの表が攻撃の弱点になります。nftablesでは
notrack(Linux 4.9以降)を優先度raw(-300)のチェーンに置き、その通信だけ接続追跡を外すことができます。
逆に、ステートフルにしておけば安心、と考えて上位の層の対策を省くのは誤りです。前の章のとおり、正常な接続の中を流れる攻撃はステートフルインスペクションでは止まりません。境界の構成全体の選び方はファイアウォールとは?仕組み・種類とWAF・UTMとの違い、企業の選び方を解説にまとめています。
よくある質問
ステートフルインスペクションとは何ですか?
通信の状態を接続表に記録し、戻りのパケットがその状態と整合するかを確かめて通すかどうかを決める、パケットフィルタリングの方式です。TCPでは状態遷移とシーケンス番号の範囲まで照合します。SPI(Stateful Packet Inspection)とも呼ばれます。
ステートフルとステートレスの違いは?
過去のパケットを覚えているかどうかです。ステートレスは1パケットずつ独立に判定するため、戻り通信用のルールを別に書く必要があります。ステートフルは自分が始めた接続の戻りを自動で通します。アプリケーション設計でいうステートレス/ステートフルの一般的な意味はステートレスとステートフルとは?違い・使い分けとシステム設計での採用判断を実装者目線で解説で説明しています。
パケットインスペクションとディープパケットインスペクションの違いは?
ステートフルパケットインスペクションが見るのは、ヘッダと接続の状態です。ディープパケットインスペクション(DPI)はペイロード(データ本体)まで読み、特定のアプリケーションや攻撃のパターンを識別します。DPIはIPSや次世代ファイアウォールの機能です。
ダイナミックパケットフィルタリングとステートフルインスペクションは同じですか?
3分類で説明する資料では区別しており、本記事も同じ整理です。動的は戻り通信の穴を自動で開ける方式、ステートフルインスペクションはそれに加えてTCPの状態の整合も確かめる方式です。現在の製品やLinuxのconntrackは両方の機能を一体で持っており、まとめて「ステートフル」と呼ばれます。
ACLとパケットフィルタリングはどう違いますか?
ACLは「この条件なら許可、この条件なら拒否」というルールの並びそのものを指します。パケットフィルタリングは、そのACLをパケットのヘッダに当てはめて通過を判定する処理です。ルーターのACLは基本的にステートレスなパケットフィルタとして動きます。