先ほどのエントリーの続きです。

「実際に筆者が施している」

Apache設定を元に「どういう動きをしているのか」を紹介します。

サンプル例

サイト名やIPアドレスなどはダミーにしています。

# ============================================================
# 【HTTP: 80番ポート】常時HTTPS(SSL/TLS)へのリダイレクト
# ============================================================
<VirtualHost *:80>
    ServerName example.com

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

# ============================================================
# 【HTTPS: 443番ポート】要塞化されたメインサーバー設定
# ============================================================
<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/html/public

    # --------------------------------------------------------
    # 1. アクセスログの間引き(ノイズカット)設定
    # --------------------------------------------------------
    # 自身の監視用IPなど、ログに記録させたくないIPを指定
    SetEnvIf Remote_Addr "192.168.1.100" dontlog
    SetEnvIf Remote_Addr "10.0.0.1" dontlog

    # 検索エンジンのクローラー(健全なBot)もログから除外してノイズを減らす
    SetEnvIfNoCase User-Agent "Googlebot" dontlog
    SetEnvIfNoCase User-Agent "GoogleOther" dontlog

    # 【外部ファイル連携】定期的・自動的に更新する悪質ボットのリストを読み込む
    # ※ファイル内で「SetEnv bad_bot 1」などのフラグを立てる想定
    Include /etc/apache2/conf-available/blacklist-bots.txt

    # dontlogフラグが付いたアクセスは記録しない
    CustomLog /var/log/apache2/example_access.log combined env=!dontlog
    ErrorLog /var/log/apache2/example_error.log

    # --------------------------------------------------------
    # 2. メインディレクトリ制御(mod_rewrite × 環境変数)
    # --------------------------------------------------------
    <Directory /var/www/html/public>
        Options -MultiViews
        AllowOverride All

        # 大量の拒否アクセスによるエラーログ肥大化を抑制(重大エラーのみ記録)
        LogLevel authz_core:crit

        <IfModule mod_rewrite.c>
            RewriteEngine On

            # 【攻撃検知】特定の動的ページに対する「大量のタグ連結」などのボット挙動を迎撃
            # 例:特定のURLパスにアクセスがあり、かつクエリにURLエンコードされたカンマ等が大量に含まれる場合
            SetEnvIf Request_URI "^/search/tags" is_target_page
            SetEnvIf Query_String "tag=.*(%2c|,|%e3%80%81).*(%2c|,|%e3%80%81).*(%2c|,|%e3%80%81)" bad_tag_stacking

            # 条件に合致したら、ログを残さず「404 Not Found(存在しない)」を返して虚無へ葬る
            RewriteCond %{ENV:is_target_page} 1
            RewriteCond %{ENV:bad_tag_stacking} 1
            RewriteRule ^ - [E=dontlog:1,R=404,L]

            # 【外部ファイル連携】スパムIPアドレスのブラックリストを読み込んで404を返す
            Include /etc/apache2/conf-available/spam-ips.txt
        </IfModule>

        # 【アクセス拒否】上記の設定や外部リストで「bad_bot」と判定された通信を遮断
        <RequireAll>
            Require not env bad_bot
            Require all granted
        </RequireAll>
    </Directory>

    # 403 Forbidden(拒否)を返すと攻撃者に「防御されている」とバレるため、
    # 403の際も「404 Not Found(最初から何も無い)」として処理する
    ErrorDocument 403 /404.html

    # --------------------------------------------------------
    # 3. セキュリティヘッダーの強化(mod_headers)
    # --------------------------------------------------------
    Header always set Strict-Transport-Security "max-age=63072000"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-XSS-Protection "1; mode=block"

    # --------------------------------------------------------
    # 4. Nepenthes(ウツボカズラ)トラップ設定(mod_alias)
    # --------------------------------------------------------
    # 攻撃者が盲目的にスキャンしてくる「脆弱性のあるパス」を、ダミーの静的ファイルへ吸い込ませる
    <IfModule mod_alias.c>
        # WordPressを使っていない(または構成が違う)のに狙われるパス
        Alias /wp-login.php /var/www/nepenthes/dummy_login.html
        Alias /wp-admin     /var/www/nepenthes/dummy_login.html
        Alias /wordpress    /var/www/nepenthes/dummy_login.html

        # 漏洩すると致命的な .git ディレクトリへのスキャン対策
        Alias /.git         /var/www/nepenthes/dummy_git.html

        # robots.txtで「巡回禁止」にしているにもかかわらず、
        # 行儀悪くスクラップ(収集)しにくるAI自動巡回エージェント用のトラップ
        Alias /assets-archive /var/www/nepenthes/dummy_login.html

        # トラップ用ディレクトリへのアクセスを許可
        <Directory /var/www/nepenthes>
            Require all granted
        </Directory>
    </IfModule>

    # --------------------------------------------------------
    # 5. SSL/TLS暗号化プロトコル設定
    # --------------------------------------------------------
    SSLEngine on
    Protocols h2 http/1.1

    # 安全性の低い古いプロトコルを徹底排除(TLS 1.2 / 1.3 のみ許可)
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 -TLSv1.2
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384
    SSLHonorCipherOrder off
    SSLSessionTickets off

    SSLCertificateFile    /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile /etc/ssl/private/example.com.key

    # --------------------------------------------------------
    # 6. WAF(ModSecurity)のチューニング
    # --------------------------------------------------------
    <IfModule security2_module>
        SecRuleEngine On

        # ファイルアップロードの容量制限を引き上げ(必要に応じて調整)
        SecRequestBodyInMemoryLimit 524288000
        SecRequestBodyLimit         524288000
        SecRequestBodyNoFilesLimit  524288000

        # --- 偽陽性(誤検知)の除外ルール ---
        # ※システム(RedmineやWordPressなど)の特性に応じて、正常な通信が遮断されないよう調整
        SecRuleRemoveById 920420 # 特定JavaScriptの誤検知対策
        SecRuleRemoveById 200004 # マルチパート解析エラーの除外
        SecRuleRemoveById 920300 # HTTPプロトコル違反の除外
        SecRuleRemoveById 920260
        SecRuleRemoveById 920270
        SecRuleRemoveById 920240

        # --- 記憶抹消刑(Damnatio Memoriae)システム ---
        # あらかじめリスト化した凶悪なIP(negativelist.txt)からのアクセスは、
        # 404エラーを返しつつ、Apacheのログ(auditlog等含む)に一切記録させず存在を抹消する
        SecRule REMOTE_ADDR "@pmFromFile negativelist.txt" "phase:1,id:2,status:404,msg:'Damnatio Memoriae',nolog,noauditlog"
    </IfModule>
</VirtualHost>

では、各設定の意図は後回しにして、「どういう動きなのか」を見てみましょう。

パターン1: http→httpsへの変更

http(80番)で来たアクセスを強制的にhttps(443)に転送します。

sequenceDiagram autonumber participant Client as ユーザー / 攻撃者 participant Apache80 as Apache (ポート80) Client->>Apache80: HTTPでアクセス (http://example.com) Note over Apache80: RewriteEngine On<br/>RewriteCond %{HTTPS} off Apache80-->>Client: 301 Moved Permanently (https://...)

パターン2: 通常アクセス

悪意を持たないアクセスには正常に通信します。

sequenceDiagram autonumber participant User as 通常ユーザー (または Googlebot) participant Apache443 as Apache (ポート443) participant WebPage as メインコンテンツ (/public) User->>Apache443: HTTPSでアクセス (正常なリクエスト) alt Googlebot や 監視IP の場合 Note over Apache443: SetEnvIf で「dontlog」フラグを付与 Note over Apache443: アクセスログ(example_access.log)へは記録しない else 一般の通常ユーザーの場合 Note over Apache443: 通常通りアクセスログに記録 end Apache443->>WebPage: コンテンツ読み込み WebPage-->>Apache443: ページデータ返却 Note over Apache443: セキュリティヘッダーを付与<br/>(HSTS / X-Content-Type-Options / X-Frame-Options / X-XSS) Apache443-->>User: 200 OK (安全な通信でWebページを表示)

パターン3:攻撃者、ボットなど

スクレイピングや事前に設定していた悪質なボットにどう立ち向かうのかがこちらです。

sequenceDiagram autonumber participant Attacker as 攻撃者 / 悪質ボット participant Apache443 as Apache (ポート443) participant Trap as トラップエリア (/nepenthes) alt パターンA:特定の動的ページへの大量タグ攻撃 Attacker->>Apache443: /search/tags に大量のカンマを含むクエリでアクセス Note over Apache443: bad_tag_stacking 検知 Note over Apache443: E=dontlog:1 (ログを残さない) Apache443-->>Attacker: 404 Not Found (虚無へ葬る) else パターンB:ブラックリスト(blacklist-bots.txt / spam-ips.txt)に該当 Attacker->>Apache443: スパムIPや悪質Botからのアクセス Note over Apache443: Require not env bad_bot で拒否 Note over Apache443: ErrorDocument 403 /404.html Apache443-->>Attacker: 404 Not Found (403を隠蔽して最初から何も無いと騙す) else パターンC:ウツボカズラ(Nepenthes)トラップへの盲目スキャン Attacker->>Apache443: /wp-login.php や /.git へのアクセス Note over Apache443: mod_alias でダミーファイルへ転送 Apache443->>Trap: dummy_login.html などを読み込み Trap-->>Apache443: ダミーデータ Apache443-->>Attacker: 200 OK (ダミーファイルを返して時間を稼ぐ) else パターンD:凶悪なIPリスト(negativelist.txt)に該当 [WAF制御] Attacker->>Apache443: 凶悪リストに載っているIPからのアクセス Note over Apache443: ModSecurity: 'Damnatio Memoriae' 発動 Note over Apache443: nolog, noauditlog (全てのログ・監査ログから存在を抹消) Apache443-->>Attacker: 404 Not Found (記憶抹消刑) end

と、このように、

「“アクセス”は通す
 “攻撃”は阻止する
 ミドルウェアで“両方”やるというのは
 そう難しいことじゃあないな」

と言えるのが「個人VPSでApacheを使う理由」と言えます。

次は、それらを可能にする仕組みについて解説します。