第5章: パケットフィルタリング理論とファイアウォールアーキテクチャ - ネットワーク防御の計算機科学的基盤

5.1 ファイアウォールの歴史的発展

ネットワークセキュリティの黎明期

1969年のARPANET誕生当初、ネットワークセキュリティは主要な懸念事項ではありませんでした。参加者は相互に信頼された研究機関であり、ネットワークは比較的小規模でした。

1980年代、インターネットの商用利用が始まると、状況が一変しました。1988年のMorris Wormはインターネットに接続された約6,000台のコンピュータ(当時の約10%)に感染し、ネットワークセキュリティの必要性を劇的に示しました。

> "Morris Wormは、インターネットが信頼に基づく設計であることを暴露した。" — Clifford Stoll, 1989

第一世代: パケットフィルタ(1988年)

Digital Equipment Corporation(DEC)のエンジニアは、最初のパケットフィルタリングファイアウォールを開発しました。

パケットフィルタの動作原理:

入力パケット
    ↓
┌─────────────────────────────────────┐
│          パケットヘッダ検査         │
│  ┌─────────────────────────────┐   │
│  │ 送信元IP: 192.168.1.100      │   │
│  │ 宛先IP: 10.0.2.15            │   │
│  │ プロトコル: TCP              │   │
│  │ 送信元ポート: 54321          │   │
│  │ 宛先ポート: 22               │   │
│  └─────────────────────────────┘   │
│              ↓                      │
│         ルールと照合               │
│              ↓                      │
│      許可 / 拒否 / ドロップ        │
└─────────────────────────────────────┘
    ↓
出力(許可された場合)

特徴:

  • ステートレス: 各パケットを独立して評価
  • 高速: ヘッダのみを検査
  • 単純: ルールが明確

制限:

  • 接続の状態を追跡しない
  • アプリケーション層を検査しない
  • TCP接続の正当性を検証できない
  • 第二世代: ステートフルインスペクション(1994年)

    1994年、Check Point Software Technologies(Gil ShwedとShlomo Kramer)はステートフルインスペクションを発明しました。この技術はファイアウォールに革命をもたらしました。

    ステートフルインスペクションの概念:

    ┌─────────────────────────────────────────────┐
    │            接続追跡テーブル                 │
    │  ┌───────────────────────────────────────┐ │
    │  │ 接続1: 192.168.1.100:54321 →          │ │
    │  │        10.0.2.15:22 [ESTABLISHED]     │ │
    │  │ 接続2: 192.168.1.101:54322 →          │ │
    │  │        10.0.2.15:80 [SYN_SENT]        │ │
    │  │ 接続3: 192.168.1.102:54323 →          │ │
    │  │        10.0.2.15:443 [TIME_WAIT]      │ │
    │  └───────────────────────────────────────┘ │
    └─────────────────────────────────────────────┘
    
    新しいパケット到着時:
    1. 既存の接続に属するか確認
    2. 属する場合: 接続状態に基づいて許可/拒否
    3. 属さない場合: ルールに基づいて評価
    
    利点:
    - TCPの3ウェイハンドシェイクを追跡
    - 不正なパケット(ACKなしでFIN等)を検出
    - 応答パケットを自動的に許可
    

    第三世代: アプリケーション層ファイアウォール

    1990年代後半、プロキシファイアウォールディープパケットインスペクション(DPI)が登場しました。

    従来のファイアウォール:
      Layer 3-4のみ検査(IP, TCP/UDP)
    
    アプリケーション層ファイアウォール:
      Layer 7まで検査(HTTP, FTP, DNS, etc.)
    
    例: HTTPリクエストの検査
      GET /admin/delete_user.php HTTP/1.1
      Host: example.com
      Cookie: session=malicious_script
    
      → SQLインジェクション検出
      → 不正なパスへのアクセス検出
      → 悪意のあるペイロード検出
    

    現代のファイアウォール: 次世代ファイアウォール(NGFW)

    2000年代以降、次世代ファイアウォール(Next-Generation Firewall)が登場しました:

  • アプリケーション認識: アプリケーションを識別し制御
  • 統合脅威管理(UTM): IPS、アンチウイルス、URLフィルタリング
  • SSL/TLS検査: 暗号化トラフィックの復号と検査
  • サンドボックス: 未知のファイルの動的解析

5.2 OSI参照モデルとパケット処理

OSI 7層モデル

1984年、ISOはOSI参照モデル(Open Systems Interconnection Reference Model)を標準化しました。ネットワーク通信を7つの抽象層に分割します:

Layer 7: アプリケーション層  │ HTTP, FTP, SSH, DNS
Layer 6: プレゼンテーション層 │ SSL/TLS, 暗号化, 圧縮
Layer 5: セッション層        │ セッション管理, RPC
Layer 4: トランスポート層    │ TCP, UDP, ポート番号
Layer 3: ネットワーク層      │ IP, ICMP, ルーティング
Layer 2: データリンク層      │ Ethernet, MAC アドレス
Layer 1: 物理層              │ 電気信号, ケーブル

パケットのカプセル化

データは各層でカプセル化されます:

アプリケーションデータ
        ↓ [Layer 7]
┌─────────────────────────────────────┐
│            HTTP Request             │
└─────────────────────────────────────┘
        ↓ [Layer 4: TCP]
┌─────────┬───────────────────────────┐
│TCP Header│      HTTP Request         │
│ SRC: 54321                          │
│ DST: 80  │                          │
└─────────┴───────────────────────────┘
        ↓ [Layer 3: IP]
┌─────────┬─────────┬─────────────────┐
│IP Header│TCP Header│  HTTP Request   │
│SRC: 192.168.1.100                   │
│DST: 93.184.216.34                   │
└─────────┴─────────┴─────────────────┘
        ↓ [Layer 2: Ethernet]
┌─────────────┬─────────┬─────────┬───┐
│Ethernet Hdr │IP Header│TCP Hdr  │...│
│MAC addresses│         │         │   │
└─────────────┴─────────┴─────────┴───┘

ファイアウォールの動作層

パケットフィルタ(第一世代):
  Layer 3-4: IP アドレス、ポート番号

ステートフルファイアウォール(第二世代):
  Layer 3-4 + 接続状態追跡

アプリケーションファイアウォール(第三世代):
  Layer 3-7: プロトコル内容まで検査

UFW/iptables:
  主に Layer 3-4、一部 Layer 7

5.3 Linuxカーネルのnetfilterアーキテクチャ

netfilterフレームワーク

netfilterは、Linuxカーネル2.4(2001年)で導入されたパケットフィルタリングフレームワークです。Paul "Rusty" Russellが開発しました。

┌─────────────────────────────────────────────────────────┐
│                  Linuxカーネル空間                      │
│  ┌────────────────────────────────────────────────┐    │
│  │               netfilter フレームワーク          │    │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐          │    │
│  │  │ filter  │ │  nat    │ │ mangle  │          │    │
│  │  │ テーブル│ │テーブル │ │テーブル │          │    │
│  │  └─────────┘ └─────────┘ └─────────┘          │    │
│  └────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────┘
                           ↑
                     Netlink ソケット
                           ↓
┌─────────────────────────────────────────────────────────┐
│                  ユーザー空間                           │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐         │
│  │ iptables │    │  nftables │    │   UFW    │         │
│  └──────────┘    └──────────┘    └──────────┘         │
└─────────────────────────────────────────────────────────┘

netfilterのフック(Hook)

パケットがカーネルを通過する際、5つのフックポイントでnetfilterが介入できます:

                     ┌─────────────────┐
入力パケット ────────→│  PREROUTING     │
                     └────────┬────────┘
                              ↓
                     ┌────────────────┐
                     │ ルーティング   │
                     │   決定         │
                     └───────┬────────┘
                             │
            ┌────────────────┴────────────────┐
            ↓                                 ↓
   ┌─────────────────┐               ┌─────────────────┐
   │     INPUT       │               │    FORWARD      │
   │  (ローカル宛) │               │  (転送トラフィック)│
   └────────┬────────┘               └────────┬────────┘
            ↓                                 │
   ┌─────────────────┐                        │
   │ ローカルプロセス│                        │
   └────────┬────────┘                        │
            ↓                                 │
   ┌─────────────────┐                        │
   │    OUTPUT       │                        │
   │ (ローカル発信)│                        │
   └────────┬────────┘                        │
            ↓                                 ↓
            └────────────────┬────────────────┘
                             ↓
                     ┌─────────────────┐
                     │  POSTROUTING    │
                     └────────┬────────┘
                              ↓
                        出力パケット

テーブルとチェーン

netfilterは複数のテーブルを使用し、各テーブルにはチェーンが含まれます:

filterテーブル(デフォルト):

用途: パケットのフィルタリング(許可/拒否)
チェーン:
  - INPUT: ローカルプロセス宛のパケット
  - FORWARD: 転送されるパケット
  - OUTPUT: ローカルプロセスが生成したパケット

natテーブル:

用途: ネットワークアドレス変換
チェーン:
  - PREROUTING: 宛先NAT(DNAT)
  - OUTPUT: ローカル生成パケットのDNAT
  - POSTROUTING: 送信元NAT(SNAT/マスカレード)

mangleテーブル:

用途: パケットヘッダの変更(TOS, TTLなど)
チェーン: すべてのフックポイント

接続追跡(conntrack)

conntrackモジュールは、ステートフルインスペクションを実現します:

接続状態:
  NEW:         新しい接続の最初のパケット
  ESTABLISHED: 確立された接続に属するパケット
  RELATED:     関連する接続(FTPデータ接続など)
  INVALID:     状態を識別できないパケット

例: TCPハンドシェイク
  SYN →        状態: NEW
  ← SYN-ACK    状態: ESTABLISHED
  ACK →        状態: ESTABLISHED
  (以降のパケット) 状態: ESTABLISHED

接続追跡により、応答パケットを自動的に許可できます:

# iptablesでの接続追跡ルール
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

5.4 iptablesからUFWへ

iptablesの複雑さ

iptablesは強力ですが、構文が複雑です:

# SSHポート22を許可(IPv4)
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED -j ACCEPT

# IPv6も必要
ip6tables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED -j ACCEPT

# デフォルトポリシー
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# ループバック許可
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# ICMP(ping)許可
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

UFW: 抽象化による簡素化

UFW(Uncomplicated Firewall)は、2008年にUbuntuプロジェクトで開発されました。iptablesの複雑さを隠蔽し、シンプルなインターフェースを提供します:

# 上記のiptablesルールをUFWで書くと:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable

# たった4コマンドで同等の設定が完了

UFWのアーキテクチャ

┌─────────────────────────────────────────────┐
│              ユーザーコマンド               │
│         sudo ufw allow 4242/tcp            │
└────────────────────┬────────────────────────┘
                     ↓
┌─────────────────────────────────────────────┐
│           UFW(Pythonスクリプト)           │
│  /usr/sbin/ufw                              │
│  /usr/share/ufw/                            │
└────────────────────┬────────────────────────┘
                     ↓
┌─────────────────────────────────────────────┐
│          UFW設定ファイル                    │
│  /etc/ufw/user.rules                       │
│  /etc/ufw/user6.rules(IPv6)              │
│  /etc/ufw/before.rules                     │
│  /etc/ufw/after.rules                      │
└────────────────────┬────────────────────────┘
                     ↓
┌─────────────────────────────────────────────┐
│       iptables / ip6tables                  │
│       ルールに変換                          │
└────────────────────┬────────────────────────┘
                     ↓
┌─────────────────────────────────────────────┐
│          netfilter(カーネル)              │
└─────────────────────────────────────────────┘

5.5 多層防御(Defense in Depth)

多層防御の理論

多層防御(Defense in Depth)は、軍事戦略から借用されたセキュリティ概念です。単一の防御層に依存するのではなく、複数の独立した防御層を重ねます。

攻撃者の視点:
┌─────────────────────────────────────────────────────┐
│                   外部ネットワーク                  │
└───────────────────────┬─────────────────────────────┘
                        ↓ Layer 1: 境界ファイアウォール
┌─────────────────────────────────────────────────────┐
│                      DMZ                            │
└───────────────────────┬─────────────────────────────┘
                        ↓ Layer 2: 内部ファイアウォール
┌─────────────────────────────────────────────────────┐
│                 内部ネットワーク                    │
└───────────────────────┬─────────────────────────────┘
                        ↓ Layer 3: ホストファイアウォール(UFW)
┌─────────────────────────────────────────────────────┐
│                   ホストマシン                      │
└───────────────────────┬─────────────────────────────┘
                        ↓ Layer 4: アプリケーションセキュリティ
┌─────────────────────────────────────────────────────┐
│                     SSH設定                         │
│            (ポート変更、鍵認証、etc.)               │
└───────────────────────┬─────────────────────────────┘
                        ↓ Layer 5: アクセス制御
┌─────────────────────────────────────────────────────┐
│               sudo設定、パスワードポリシー          │
└─────────────────────────────────────────────────────┘

各層を突破するには、その層の防御を破る必要がある
→ 攻撃コストが累積的に増加

Born2berootでの多層防御

Layer 1: ファイアウォール(UFW)
  - ポート4242のみ開放
  - その他すべてブロック

Layer 2: SSHセキュリティ
  - 非標準ポート(4242)
  - rootログイン禁止
  - 認証試行回数制限

Layer 3: アクセス制御
  - sudo設定
  - パスワードポリシー
  - 監査ログ

Layer 4: システム強化
  - パスワード複雑性要件
  - サービス最小化
  - 定期的な監視

最小権限の原則の適用

ファイアウォール設定は最小権限の原則に従います:

悪い設計:
  デフォルト: ALLOW
  明示的に危険なポートをブロック
  → 新しいサービスを忘れる可能性
  → 未知の脆弱性にさらされる

良い設計(Born2beroot):
  デフォルト: DENY
  必要なポートのみ明示的に許可
  → 最小限のアタックサーフェス
  → 忘れても安全側に倒れる

---

5.6 Born2berootのUFW設定

理論的基盤を理解したところで、Born2berootプロジェクトのUFW設定を実装します。

UFWのインストール

# パッケージリストを更新
sudo apt update

# UFWをインストール
sudo apt install ufw -y

# インストール確認
dpkg -l | grep ufw

# バージョン確認
sudo ufw version

デフォルトポリシーの設定

第5.5節で説明した最小権限の原則に基づき、デフォルトポリシーを設定します:

# 入力をデフォルトで拒否(セキュア)
sudo ufw default deny incoming

# 出力をデフォルトで許可(インターネット使用に必要)
sudo ufw default allow outgoing

# 設定確認
sudo ufw status verbose

SSH(ポート4242)の許可

Born2berootでは、ポート4242のみを開放します:

# ポート4242/TCPを許可
sudo ufw allow 4242/tcp

# コメント付きで追加(推奨)
sudo ufw allow 4242/tcp comment 'SSH Born2beroot'

# 確認
sudo ufw status numbered

理論的根拠:

  • 第4章で設定したSSHはポート4242を使用
  • その他のポートは不要なためブロック

UFWの有効化

# UFWを有効化
sudo ufw enable

# 警告メッセージ:
# Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
# Firewall is active and enabled on system startup

# 状態確認
sudo ufw status verbose
# 出力:
# Status: active
# Logging: on (low)
# Default: deny (incoming), allow (outgoing), disabled (routed)
#
# To                         Action      From
# --                         ------      ----
# 4242/tcp                   ALLOW IN    Anywhere
# 4242/tcp (v6)              ALLOW IN    Anywhere (v6)

システム起動時の自動有効化

# UFWをシステム起動時に自動有効化
sudo systemctl enable ufw

# 確認
sudo systemctl is-enabled ufw

5.7 UFWルール管理

ルールの追加と削除

# ポートを許可
sudo ufw allow 80/tcp      # HTTP
sudo ufw allow 443/tcp     # HTTPS

# ポート範囲を許可
sudo ufw allow 6000:6007/tcp

# 特定のIPアドレスからの接続を許可
sudo ufw allow from 192.168.1.100 to any port 4242

# ルールを番号付きで表示
sudo ufw status numbered

# 番号でルールを削除
sudo ufw delete 2

# ルールを直接指定して削除
sudo ufw delete allow 80/tcp

ルールの優先順位

UFWルールは上から順に評価されます。最初にマッチしたルールが適用されます:

# 例: IPアドレス192.168.1.100からのSSHをブロック、他は許可
sudo ufw deny from 192.168.1.100 to any port 4242
sudo ufw allow 4242/tcp

# ルールの順序を確認
sudo ufw status numbered
# [ 1] 4242/tcp                   DENY IN     192.168.1.100
# [ 2] 4242/tcp                   ALLOW IN    Anywhere

# 192.168.1.100からはルール1でブロック
# 他のIPからはルール2で許可

ログ記録

# ログ記録を有効化
sudo ufw logging on

# ログレベル設定
sudo ufw logging low     # 推奨
sudo ufw logging medium
sudo ufw logging high    # 詳細(ディスク使用量注意)

# ログの確認
sudo tail -f /var/log/ufw.log

# ブロックされた接続を確認
sudo grep "UFW BLOCK" /var/log/ufw.log | tail -10

ログ形式の解読:

Dec  7 15:00:01 hostname kernel: [UFW BLOCK] IN=enp0s3 OUT=
MAC=... SRC=192.168.1.100 DST=10.0.2.15 LEN=60 TOS=0x00
PREC=0x00 TTL=64 ID=12345 PROTO=TCP SPT=54321 DPT=80
WINDOW=65535 RES=0x00 SYN URGP=0

解読:
  [UFW BLOCK]: パケットがブロックされた
  IN=enp0s3: 入力インターフェース
  SRC=192.168.1.100: 送信元IP
  DST=10.0.2.15: 宛先IP
  PROTO=TCP: プロトコル
  SPT=54321: 送信元ポート
  DPT=80: 宛先ポート(HTTPがブロックされた)

5.8 ネットワーク診断

ポートの確認

# リスニングしているポートを表示
sudo ss -tlnp
# または
sudo netstat -tlnp

# 出力例:
# State   Recv-Q Send-Q  Local Address:Port  Peer Address:Port Process
# LISTEN  0      128     0.0.0.0:4242        0.0.0.0:*     users:(("sshd",pid=612,fd=3))

# オプションの意味:
# -t: TCP
# -l: リスニングソケット
# -n: 数値で表示(名前解決しない)
# -p: プロセス情報

接続テスト

# ポートへの接続テスト(netcat)
nc -zv localhost 4242
# 出力: Connection to localhost 4242 port [tcp/*] succeeded!

nc -zv localhost 22
# 出力: nc: connect to localhost port 22 (tcp) failed: Connection refused

# ping(ICMP)
ping -c 4 8.8.8.8

# 経路追跡
traceroute google.com

# DNS解決
nslookup google.com
dig google.com

ファイアウォールルールの確認

# UFWの状態(簡潔)
sudo ufw status

# UFWの状態(詳細)
sudo ufw status verbose

# 番号付き(削除用)
sudo ufw status numbered

# 生のiptablesルールを表示
sudo iptables -L -n -v
sudo iptables -L -n -v -t nat

5.9 実践演習

シナリオ1: 新しいポートの開放と閉鎖

# 1. 現在のルールを確認
sudo ufw status numbered

# 2. ポート8080を開放
sudo ufw allow 8080/tcp

# 3. 確認
sudo ufw status

# 4. ポート8080を閉鎖
sudo ufw delete allow 8080/tcp

# 5. 確認
sudo ufw status

シナリオ2: ファイアウォールのテスト

# 1. SSH接続テスト(許可されているはず)
ssh username@localhost -p 4242

# 2. 別のポートへの接続テスト(拒否されるはず)
nc -zv localhost 22
# 出力: Connection refused

# 3. UFWログでブロックを確認
sudo grep "UFW BLOCK" /var/log/ufw.log | tail -5

シナリオ3: ルールのリセット

# すべてのルールを削除してデフォルトに戻す
sudo ufw reset

# 警告: すべてのルールが削除される
# 必要なルールを再度追加
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 4242/tcp
sudo ufw enable

5.10 トラブルシューティング

UFW有効化後にSSH接続が切れる

原因: SSHポートを開放する前にUFWを有効化した

解決:

# 仮想マシンのコンソールから直接ログイン
# (VirtualBoxウィンドウで操作)

# UFWを無効化
sudo ufw disable

# SSHポートを開放
sudo ufw allow 4242/tcp

# UFWを再有効化
sudo ufw enable

ルールを追加しても接続できない

解決:

# UFWをリロード
sudo ufw reload

# SSHサービスが起動しているか確認
sudo systemctl status ssh

# ポートがリスニングしているか確認
sudo ss -tlnp | grep 4242

# ルールの順序を確認(denyルールが先にないか)
sudo ufw status numbered

5.11 理論と実践の統合

この章で学んだ概念の関係:

歴史的発展
├── パケットフィルタ(1988)→ ステートレス検査
├── ステートフルインスペクション(1994)→ 接続追跡
└── アプリケーションファイアウォール → Layer 7検査

Linuxアーキテクチャ
├── netfilter(カーネル)
│   ├── フック: PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING
│   ├── テーブル: filter, nat, mangle
│   └── conntrack: 接続状態追跡
├── iptables(ユーザー空間)
└── UFW(抽象化層)

セキュリティ原則
├── 最小権限 → デフォルト拒否
├── 多層防御 → 複数の防御層
└── フェイルセーフ → 忘れても安全側

Born2beroot実装
├── default deny incoming
├── default allow outgoing
├── allow 4242/tcp(SSHのみ)
└── logging on

5.12 次章への準備

次章(最終章)ではパスワードポリシーと監視スクリプトを学びます:

  • パスワードエントロピーの理論
  • PAMモジュールによるポリシー強制
  • シェルスクリプトによるシステム監視
  • cronによるタスクスケジューリング

次章に進む前に、スナップショットを作成してください:

VBoxManage snapshot "Born2beroot" take "After Firewall Config" \
  --description "UFW configured, port 4242 only"