構成するファイル群

Apacheバーチャルサイト

<VirtualHost *:80>
    ServerName your-domain.com
    # HTTPでアクセスが来たらHTTPSにリダイレクト
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName your-domain.com
    DocumentRoot /var/www/your-domain/public

    # --- ログ設定 ---
    # 特定のIPからのアクセスをログに記録しない例
    SetEnvIf Remote_Addr "192.168.0.100" dontlog
    SetEnvIf Remote_Addr "192.168.0.101" dontlog
    # 特定のUser-Agent(Googlebotなど)をログに記録しない例
    SetEnvIfNoCase User-Agent "Googlebot" dontlog

    # botのアクセスリストを外部ファイルから読み込む
    Include /etc/apache2/conf-enabled/bad-bot-list.conf

    # dontlogが設定されていないアクセスのみログに記録
    CustomLog /var/log/apache2/your-domain.access.log combined env=!dontlog
    ErrorLog /var/log/apache2/your-domain.error.log

    <Directory /var/www/your-domain/public>
        Options -MultiViews
        AllowOverride All
        # アクセス拒否時に記録されるAH01630エラーを抑制
        LogLevel authz_core:crit

        <IfModule mod_rewrite.c>
            RewriteEngine On
            # IPベースのブロックリストを読み込む
            Include /etc/apache2/conf-enabled/ip-blacklist.conf
        </IfModule>

        <RequireAll>
            # bad_bot変数がセットされていたらアクセスを拒否
            Require not env bad_bot
            # それ以外は許可
            Require all granted
        </RequireAll>
    </Directory>

    # アクセス拒否時(403)に404ページを表示する
    ErrorDocument 403 /404.html

    # --- セキュリティヘッダー ---
    Header always set Strict-Transport-Security "max-age=63072000"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"

    # --- SSL/TLS設定 ---
    SSLEngine on
    Protocols h2 http/1.1
    # 推奨プロトコル設定 (TLS 1.3を優先)
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 -TLSv1.2
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    SSLHonorCipherOrder off
    SSLSessionTickets off

    SSLCertificateFile /etc/ssl/certs/your-domain.com.pem
    SSLCertificateKeyFile /etc/ssl/private/your-domain.com.key

    # --- ModSecurity設定 ---
    <IfModule security2_module>
        SecRuleEngine On

        # ファイルアップロードの上限設定
        SecRequestBodyLimit 524288000
        SecRequestBodyNoFilesLimit 524288000

        # CRS(Core Rule Set)の例外ルール
        # 特定のルールIDを無効化する例
        SecRuleRemoveById 920420
        SecRuleRemoveById 200004

        # IPアドレスのブラックリスト(テキストファイル)を読み込み、
        # 一致した場合はログも残さず接続を拒否する
        SecRule REMOTE_ADDR "@pmFromFile /etc/modsecurity/ip-blacklist.txt" \
            "phase:1,id:1001,status:404,msg:'IP Blacklisted',nolog,noauditlog"
    </IfModule>

</VirtualHost>

この意図は

  • インターネット環境で必須となっている
    • 常時SSL化
    • 適切なセキュリティヘッダーの付与
  • 自宅など、自分のアクセスログを残さない
  • 過剰なクローラーを排除し、サーバの負荷を抑える。
  • クローラーのエージェントすら無視するアクセス元はアクセスさせない
  • Mod_Securityが検知したIPアドレスをリスト化し、再攻撃をさせない

仕組みです。

そして、重要なのは、403(Forbidden)に対して404(Not Found)を返す処置です。

これを行わず403としてしまうと、攻撃者は「ここには『そうまでして守りたい貴重な情報がある』に違いない。なら別の手段を試みよう」という心理が働きます。そのため「ここには何もない」と示すことで、追及の手を緩めさせる意図があります。

bad-bot listの例

以下に示すのは、筆者が実際に出会った「robots.txtを無視し、過剰なまでのクローリングを繰り返す」リストです。

SetEnvIfNoCase User-Agent "facebookexternalhit/1\.1" bad_bot dontlog
SetEnvIfNoCase User-Agent "SemrushBot/7~bl" bad_bot dontlog
SetEnvIfNoCase User-Agent "AhrefsBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "MJ12bot" bad_bot dontlog
SetEnvIfNoCase User-Agent "DotBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "Baiduspider" bad_bot dontlog
SetEnvIfNoCase User-Agent "YandexBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "Sogou web spider" bad_bot dontlog
SetEnvIfNoCase User-Agent "Exabot" bad_bot dontlog
SetEnvIfNoCase User-Agent "MegaIndex\.ru" bad_bot dontlog
SetEnvIfNoCase User-Agent "SeznamBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "BLEXBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "Bytespider" bad_bot dontlog
SetEnvIfNoCase User-Agent "DataForSeoBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "serpstatbot" bad_bot dontlog
SetEnvIfNoCase User-Agent "SeekportBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "index\.community crawler" bad_bot dontlog
SetEnvIfNoCase User-Agent "PetalBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "BacklinksExtendedBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "meta-externalagent/1\.1" bad_bot dontlog
SetEnvIfNoCase User-Agent "ICC-Crawler" bad_bot dontlog
SetEnvIfNoCase User-Agent "bingbot" bad_bot dontlog
SetEnvIfNoCase User-Agent "msnbot" bad_bot dontlog
SetEnvIfNoCase User-Agent "Applebot" bad_bot dontlog
SetEnvIfNoCase User-Agent "DuckDuckBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "Majestic-SEO" bad_bot dontlog
SetEnvIfNoCase User-Agent "cognitiveSEO" bad_bot dontlog
SetEnvIfNoCase User-Agent "archive\.org_bot" bad_bot dontlog
SetEnvIfNoCase User-Agent "CCBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "Custom-AsyncHttpClient" bad_bot dontlog
SetEnvIfNoCase User-Agent "ImagesiftBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "GPTBot/1\.2" dontlog
SetEnvIfNoCase User-Agent "Barkrowler/0\.9" bad_bot dontlog
SetEnvIfNoCase User-Agent "ClaudeBot/1\.0" bad_bot dontlog
SetEnvIfNoCase User-Agent "Cypex" bad_bot dontlog
SetEnvIfNoCase User-Agent "^$" bad_bot dontlog

これらは「ログ汚染」レベルで執拗なアクセスを繰り返す、AI時代ならではの頭痛の種。これは名指しで非難しますが、facebookのbotは何かのDDoSと見まがうまでのアクセスでした。

SetEnvIfNoCase User-Agent "^$" bad_bot dontlog

最終行は、エージェント(ブラウザやクローラー)すら書いていない初歩的で機械的なクローラー/スクレイパーへの対処です。

ip-blacklist.confの内容

以下のような内容です。一部は実在のものを交えています。

#
# IPアドレスベースのアクセスブロックリスト
# -------------------------------------------------
# このファイルは、Apacheの mod_rewrite を使用して、
# 特定のIPアドレスからのアクセスを拒否するために使われます。
#
# 各行の末尾には [OR] フラグを付けます。
# ただし、ファイル全体の最後の条件となる行には [OR] を付けません。
#

# ローカルホストからのアクセスは常に許可する (ブロック対象から除外)
RewriteCond %{REMOTE_ADDR} !^127\.0\.0\.1$


# ─── 正規表現の書き方ガイド ───
#
# 例1: 単一のIPアドレスをブロック (完全一致)
# --> ^192\.0\.2\.1$
#     ^ は行の先頭、 $ は行の末尾を意味します。
#     ドット(.)は正規表現では特殊な意味を持つため、
#     バックスラッシュ(\)を付けて「\.」と記述します。
#
# 例2: 特定のネットワーク範囲(/24)をブロック
# --> ^192\.0\.2\.
#     行の末尾を示す $ を付けないことで、「192.0.2.」で始まる
#     全てのIP (192.0.2.0 ~ 192.0.2.255) をブロックします。
#
# 例3: 複数のネットワーク範囲(/23)をブロック
# --> ^198\.51\.(100|101)\.
#     ( | ) を使うことで、「198.51.100.」と「198.51.101.」の両方を
#     ブロックの対象にできます。
#
# 例4: 少し複雑な範囲をブロック
# --> ^203\.0\.113\.(1[6-9]|2[0-9]|3[0-1])\.
#     [ ] を使うことで、より複雑な範囲指定が可能です。
#     この例では「203.0.113.16」から「203.0.113.31」までをブロックします。
#

# ─── 汎用的なブロックルール (サンプル) ───

# 特定のクラウドプロバイダーからのスキャン活動 (例: AbuseIPDB等で報告多数)
# 例: 203.0.113.0/24
RewriteCond %{REMOTE_ADDR} ^203\.0\.113\. [OR]

# 特定のホスティングサービスからの広範囲な偵察活動
# 例: 198.51.100.0/23
RewriteCond %{REMOTE_ADDR} ^198\.51\.(100|101)\. [OR]

# 過去に攻撃が確認された単一のIPアドレス
RewriteCond %{REMOTE_ADDR} ^192\.0\.2\.123$ [OR]
RewriteCond %{REMOTE_ADDR} ^192\.0\.2\.234$ [OR]


# ─── ここから下に新しいルールを追記します ───
# (新しいルールには行末に [OR] を付けてください)




# ─── ここより下は編集しないでください ───
#
# ファイル内の最後のルールになります。
# この行には [OR] を付けないでください。
RewriteCond %{REMOTE_ADDR} ^192\.0\.2\.99$

このリストをエージェントと別に設定するのは「実在のブラウザ(Chrome, Firefox, Safali)を偽装して過剰なアクセスや不審な攻撃」を仕込むためのものです。

/etc/modsecurity/ip-blacklist.txt の例

# ModSecurity用 IPブラックリスト
# -------------------------------------------------
# 1行に1つのIPアドレス、またはネットワーク範囲(CIDR形式)を記述します。
# コメント行は # で始めます。
#

# 単一のIPアドレス
192.0.2.1
198.51.100.200

これは、単にIPアドレスを羅列したテキストファイル…… ですが、別項で記述する「Mod_Security等が検知したアクセス元」を追記することで、「一度でも攻撃を試みたアドレスの再侵入を許さない」仕組みにしています。