Debian/UbuntuでApacheを使用してmod securityを設定する方法
プレリュード
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_FILENAMEとform.php、REQUEST_METHODとPOST、および[ X155X] REQUEST_BODY と正規表現( @rx )文字列(pills | Insurance | rolex)。 ?i:は、大文字と小文字を区別しない一致を行います。 これら3つのルールすべてが正常に一致すると、ACTIONはdenyおよびlogに「スパムが検出されました」というメッセージが表示されます。 chain アクションは、3つのルールすべてに一致する論理積をシミュレートします。
ホストとディレクトリを除く
phpMyAdmin などのアプリケーションをmodsecurityとして実行していて、SQLクエリをブロックする場合は、特定のディレクトリまたはドメイン名を除外することが理にかなっている場合があります。 WordPressのようなCMSアプリケーションの管理バックエンドを除外することもお勧めします。
完全なVirtualHostのmodsecurityを無効にするには、次のように配置します
<IfModule security2_module>
SecRuleEngine Off
</IfModule>
<VirtualHost>セクション内。
特定のディレクトリの場合:
<Directory "/var/www/wp-admin">
<IfModule security2_module>
SecRuleEngine Off
</IfModule>
</Directory>
modsecurityを完全に無効にしたくない場合は、SecRuleRemoveByIdディレクティブを使用して、IDを指定して特定のルールまたはルールチェーンを削除します。
<LocationMatch "/wp-admin/update.php">
<IfModule security2_module>
SecRuleRemoveById 981173
</IfModule>
</LocationMatch>
参考文献
公式のmodsecurityドキュメントhttps://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual