プレリュード


Modセキュリティは、Apache、Nginx、IISで動作する無料のWebアプリケーションファイアウォール(WAF)です。 シンプルで複雑な操作を実行するための柔軟なルールエンジンをサポートし、SQLインジェクション、クロスサイトスクリプティング、トロイの木馬、悪意のあるユーザーエージェント、セッションハイジャック、その他多くのエクスプロイトのルールを含むコアルールセット(CRS)が付属しています。 Apacheの場合、これはインストールと構成を簡単にする追加モジュールです。

このチュートリアルを完了するには、サーバーにLAMPがインストールされている必要があります。

mod_securityのインストール


ModsecurityはDebian/Ubuntuリポジトリで利用できます。

apt-get install libapache2-modsecurity

mod_securityモジュールがロードされているかどうかを確認します。

apachectl -M | grep --color security

モジュールがロードされたことを示すsecurity2_module (shared)という名前のモジュールが表示されます。

Modsecurityのインストールには、名前を変更する必要がある推奨構成ファイルが含まれています。

mv /etc/modsecurity/modsecurity.conf{-recommended,}

Apacheをリロードします

service apache2 reload

mod_securityの新しいログファイルはApacheログディレクトリにあります。

root@droplet:~# ls -l /var/log/apache2/modsec_audit.log
-rw-r----- 1 root root 0 Oct 19 08:08 /var/log/apache2/modsec_audit.log

mod_securityの構成


箱から出して、modsecurityはルールが機能する必要があるため、何もしません。 デフォルトの構成ファイルはDetectionOnlyに設定されており、ルールの一致に従ってリクエストをログに記録し、何もブロックしません。 これは、modsecurity.confファイルを編集することで変更できます。

nano /etc/modsecurity/modsecurity.conf

この行を見つける

SecRuleEngine DetectionOnly

次のように変更します。

SecRuleEngine On

本番サーバーでこれを試している場合は、すべてのルールをテストした後でのみ、このディレクティブを変更してください。

変更するもう1つのディレクティブは、SecResponseBodyAccessです。 これにより、応答本文がバッファリングされるかどうかが構成されます(つまり、 modsecurityによって読み取られます)。 これは、データ漏洩の検出と保護が必要な場合にのみ必要です。 したがって、 On のままにすると、ドロップレットリソースが使い果たされ、ログファイルのサイズも大きくなります。

これを見つける

SecResponseBodyAccess On

次のように変更します。

SecResponseBodyAccess Off

次に、Webアプリケーションに投稿できる最大データを制限します。 2つのディレクティブがこれらを構成します。

SecRequestBodyLimit
SecRequestBodyNoFilesLimit

SecRequestBodyLimitディレクティブは、最大POSTデータサイズを指定します。 クライアントからそれより大きいものが送信された場合、サーバーは 413 Request Entity TooLargeエラーで応答します。 Webアプリケーションにファイルのアップロードがない場合、この値を大幅に減らすことができます。

構成ファイルに記載されている値は

SecRequestBodyLimit 13107200

これは12.5MBです。

これと同様に、SecRequestBodyNoFilesLimitディレクティブがあります。 唯一の違いは、このディレクティブがPOSTデータからファイルのアップロードを差し引いたサイズを制限することです。この値は「実用的な範囲で」低くする必要があります。

構成ファイルの値は次のとおりです。

SecRequestBodyNoFilesLimit 131072

これは128KBです。

これらのディレクティブに沿って、サーバーのパフォーマンスに影響を与えるもう1つのディレクティブSecRequestBodyInMemoryLimitがあります。 このディレクティブはほとんど自明です。 これは、メモリ(RAM)に保持する「要求本文」データ(POSTデータ)の量を指定します。それ以上のものはハードディスクに配置されます(スワッピングのように)。 ドロップレットはSSDを使用するため、これはそれほど問題にはなりません。 ただし、RAMに余裕がある場合は、これを適切な値に設定できます。

SecRequestBodyInMemoryLimit 131072

これは、構成ファイルで指定された値(128KB)です。

SQLインジェクションのテスト


ルールの構成を進める前に、SQLインジェクションに対して脆弱なPHPスクリプトを作成し、試してみます。 これは基本的なPHPログインスクリプトであり、セッション処理は行われないことに注意してください。 データベースに接続するように、以下のスクリプトのMySQLパスワードを必ず変更してください。

/var/www/login.php

<html>
<body>
<?php
    if(isset($_POST['login']))
    {
        $username = $_POST['username'];
        $password = $_POST['password'];
        $con = mysqli_connect('localhost','root','password','sample');
        $result = mysqli_query($con, "SELECT * FROM `users` WHERE username='$username' AND password='$password'");
        if(mysqli_num_rows($result) == 0)
            echo 'Invalid username or password';
        else
            echo '<h1>Logged in</h1><p>A Secret for you....</p>';
    }
    else
    {
?>
        <form action="" method="post">
            Username: <input type="text" name="username"/><br />
            Password: <input type="password" name="password"/><br />
            <input type="submit" name="login" value="Login"/>
        </form>
<?php
    }
?>
</body>
</html>

このスクリプトはログインフォームを表示します。 適切なクレデンシャルを入力すると、「ASecretforyou」というメッセージが表示されます。

データベースにクレデンシャルが必要です。 MySQLデータベースとテーブルを作成してから、ユーザー名とパスワードを挿入します。

mysql -u root -p

これにより、mysql>プロンプトが表示されます

create database sample;
connect sample;
create table users(username VARCHAR(100),password VARCHAR(100));
insert into users values('jesin','pwd');
insert into users values('alice','secret');
quit;

ブラウザを開き、http://yourwebsite.com/login.phpに移動して、正しいクレデンシャルのペアを入力します。

Username: jesin
Password: pwd

ログインが成功したことを示すメッセージが表示されます。 ここに戻って、間違ったクレデンシャルのペアを入力します。無効なユーザー名またはパスワードというメッセージが表示されます。

スクリプトが正しく機能していることを確認できます。 次の仕事は、ログインページをバイパスするためにSQLインジェクションを試してみることです。 usernameフィールドに次のように入力します。

' or true -- 

--の後にスペースがあるはずですが、このスペースがないとこのインジェクションは機能しません。 password フィールドを空のままにして、ログインボタンを押します。

出来上がり! スクリプトは、認証されたユーザー向けのメッセージを表示します。

ルールの設定


あなたの生活を楽にするために、mod_securityと一緒にすでにインストールされている多くのルールがあります。 これらはCRS(コアルールセット)と呼ばれ、

root@droplet:~# ls -l /usr/share/modsecurity-crs/
total 40
drwxr-xr-x 2 root root  4096 Oct 20 09:45 activated_rules
drwxr-xr-x 2 root root  4096 Oct 20 09:45 base_rules
drwxr-xr-x 2 root root  4096 Oct 20 09:45 experimental_rules
drwxr-xr-x 2 root root  4096 Oct 20 09:45 lua
-rw-r--r-- 1 root root 13544 Jul  2  2012 modsecurity_crs_10_setup.conf
drwxr-xr-x 2 root root  4096 Oct 20 09:45 optional_rules
drwxr-xr-x 3 root root  4096 Oct 20 09:45 util

ドキュメントは次のURLで入手できます。

root@droplet1:~# ls -l /usr/share/doc/modsecurity-crs/
total 40
-rw-r--r-- 1 root root   469 Jul  2  2012 changelog.Debian.gz
-rw-r--r-- 1 root root 12387 Jun 18  2012 changelog.gz
-rw-r--r-- 1 root root  1297 Jul  2  2012 copyright
drwxr-xr-x 3 root root  4096 Oct 20 09:45 examples
-rw-r--r-- 1 root root  1138 Mar 16  2012 README.Debian
-rw-r--r-- 1 root root  6495 Mar 16  2012 README.gz

これらのルールをロードするには、Apacheにこれらのディレクトリを調べるように指示する必要があります。 modsecurity.confファイルを編集します。

nano /etc/apache2/mods-enabled/modsecurity.conf

<IfModule security2_module> </IfModule>内に次のディレクティブを追加します。

Include "/usr/share/modsecurity-crs/*.conf"
Include "/usr/share/modsecurity-crs/activated_rules/*.conf"

activated_rulesディレクトリは、Apacheのmods-enabledディレクトリに似ています。 ルールはディレクトリで利用できます。

/usr/share/modsecurity-crs/base_rules
/usr/share/modsecurity-crs/optional_rules
/usr/share/modsecurity-crs/experimental_rules

これらをアクティブにするには、activated_rulesディレクトリ内にシンボリックリンクを作成する必要があります。 SQLインジェクションルールをアクティブにしましょう。

cd /usr/share/modsecurity-crs/activated_rules/
ln -s /usr/share/modsecurity-crs/base_rules/modsecurity_crs_41_sql_injection_attacks.conf .

ルールを有効にするには、Apacheをリロードする必要があります。

service apache2 reload

次に、前に作成したログインページを開き、ユーザー名フィールドでSQLインジェクションクエリを使用してみます。 SecRuleEngineディレクティブをOnに変更した場合は、 403Forbiddenエラーが表示されます。 DetectionOnly オプションのままにすると、インジェクションは成功しますが、試行はmodsec_audit.logファイルに記録されます。

独自のmod_securityルールを作成する


このセクションでは、特定の「スパム」単語がHTMLフォームに入力された場合に、リクエストをブロックするルールチェーンを作成します。 まず、テキストボックスから入力を取得してユーザーに表示するPHPスクリプトを作成します。

/var/www/form.php

<html>
    <body>
        <?php
            if(isset($_POST['data']))
                echo $_POST['data'];
            else
            {
        ?>
                <form method="post" action="">
                        Enter something here:<textarea name="data"></textarea>
                        <input type="submit"/>
                </form>
        <?php
            }
        ?>
    </body>
</html>

カスタムルールは、任意の構成ファイルに追加したり、modsecurityディレクトリに配置したりできます。 ルールを別の新しいファイルに配置します。

nano /etc/modsecurity/modsecurity_custom_rules.conf

このファイルに以下を追加します。

SecRule REQUEST_FILENAME "form.php" "id:'400001',chain,deny,log,msg:'Spam detected'"
SecRule REQUEST_METHOD "POST" chain
SecRule REQUEST_BODY "@rx (?i:(pills|insurance|rolex))"

ファイルを保存し、Apacheをリロードします。 ブラウザでhttp://yourwebsite.com/form.phpを開き、ピル、保険、ロレックスのいずれかの単語を含むテキストを入力します。

403ページとログエントリ、またはSecRuleEngine設定に基づくログエントリのみが表示されます。 SecRuleの構文は次のとおりです。

SecRule VARIABLES OPERATOR [ACTIONS]

ここでは、 chain アクションを使用して、変数REQUEST_FILENAMEform.phpREQUEST_METHODPOST、および[ X155X] REQUEST_BODY