Ubuntu14.04およびDebian8でApacheを使用してModSecurityを設定する方法
序章
ModSecurityは、Apache、Nginx、IISで動作する無料のWebアプリケーションファイアウォール(WAF)です。 シンプルで複雑な操作を実行するための柔軟なルールエンジンをサポートし、SQLインジェクション、クロスサイトスクリプティング、トロイの木馬、悪意のあるユーザーエージェント、セッションハイジャック、その他多くのエクスプロイトのルールを含むコアルールセット(CRS)が付属しています。 Apacheの場合、インストールと構成を簡単にする追加モジュールとしてロードされます。
前提条件
このチュートリアルに従うには、次のものが必要です。
- Ubuntu14.04またはDebian8ドロップレット。
- Ubuntu14.04またはDebian8の初期サーバーセットアップチュートリアルに従ってセットアップできるsudo特権を持つ標準ユーザーアカウント。
- Ubuntu14.04またはDebian8のチュートリアルに従ってインストールできるLAMPスタック。
ステップ1—ModSecurityのインストール
このステップでは、ModSecurityをインストールします。
まず、パッケージインデックスファイルを更新します。
sudo apt-get update
次に、ModSecurityをインストールします。
sudo apt-get install libapache2-mod-security2 -y
次のコマンドを使用して、ModSecurityモジュールがロードされたことを確認できます。
sudo apachectl -M | grep --color security2
出力がsecurity2_module (shared)
の場合、これはモジュールがロードされたことを示します。
ModSecurityのインストールには、名前を変更する必要のある推奨構成ファイルが含まれています。
sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
最後に、Apacheをリロードします。
sudo service apache2 reload
ModSecurityの新しいログファイルが/var/log/apache2/modsec_audit.log
のApacheログディレクトリに作成されます。
ステップ2—ModSecurityの構成
箱から出して、ModSecurityはルールが機能する必要があるため、何もしません。 このステップでは、最初にいくつかの構成ディレクティブを有効にします。
このステップで構成ディレクティブを見つけて置き換えるために、ストリームエディターであるsed
を使用します。 このツールの詳細については、sedチュートリアルシリーズをお読みください。
有効にする基本的なディレクティブ
デフォルトのModSecurity構成ファイルはDetectionOnly
に設定されており、ルールの一致に従って要求をログに記録し、何もブロックしません。 これは、modsecurity.conf
ファイルを編集し、SecRuleEngine
ディレクティブを変更することで変更できます。 実稼働サーバーでこれを試している場合は、すべてのルールをテストした後でのみ、このディレクティブを変更してください。
sudo sed -i "s/SecRuleEngine DetectionOnly/SecRuleEngine On/" /etc/modsecurity/modsecurity.conf
SecResponseBodyAccess
ディレクティブは、応答本文をバッファリングするかどうかを構成します(つまり、 ModSecurityによって読み取られます)。 これは、データ漏洩の検出と保護が必要な場合にのみ必要です。 したがって、オンのままにすると、Dropletリソースが使い果たされ、ログファイルのサイズも大きくなるため、オフにします。
sudo sed -i "s/SecResponseBodyAccess On/SecResponseBodyAccess Off/" /etc/modsecurity/modsecurity.conf
変更するオプションのディレクティブ
/etc/modsecurity/modsecurity.conf
を編集してカスタマイズできるディレクティブは他にもあります。 SecRequestBodyLimit
およびSecRequestBodyNoFilesLimit
ディレクティブは、Webアプリケーションに投稿できる最大データを制限します。
特に、SecRequestBodyLimit
ディレクティブは最大POSTデータサイズを指定します。 クライアントからそれより大きいものが送信された場合、サーバーは 413 Request Entity TooLargeエラーで応答します。 Webアプリケーションにファイルのアップロードがない場合は、この値をそのままにしておくことができます。 構成ファイルで指定されている事前構成値は13107200バイト(12.5MB)です。 この値を変更する場合は、次の行modsecurity.conf
を探してください。
オプションの`modsecurity.conf`ディレクティブの変更
SecRequestBodyLimit 13107200
同様に、SecRequestBodyNoFilesLimit
は、POSTデータからファイルのアップロードを差し引いたサイズを制限します。 この値は、誰かが非常に大きなサイズのリクエストボディを送信しているときに、サービス拒否(DoS)攻撃を受けやすくするために、できるだけ低く設定する必要があります。 構成ファイルの事前構成値は131072バイト(128KB)です。 この値を変更する場合は、次の行modsecurity.conf
を探してください。
オプションの`modsecurity.conf`ディレクティブの変更
SecRequestBodyNoFilesLimit 131072
サーバーのパフォーマンスに影響を与えるディレクティブはSecRequestBodyInMemoryLimit
です。 このディレクティブはほとんど自明です。 これは、メモリ(RAM)に保持する「要求本文」データ(POSTデータ)の量を指定します。それ以上のものは(スワッピングのように)ハードディスクに配置されます。 ドロップレットはSSDを使用するため、これはそれほど問題にはなりません。 ただし、RAMに余裕がある場合は、これを変更できます。 このディレクティブの事前構成された値は128KBです。 この値を変更する場合は、次の行modsecurity.conf
を探してください。
オプションの`modsecurity.conf`ディレクティブの変更
SecRequestBodyInMemoryLimit 131072
ステップ3—SQLインジェクションのテスト
いくつかのルールを構成する前に、ModSecurityの保護をテストするためにSQLインジェクションに対して脆弱なPHPスクリプトを作成します。
注:これは、セッション処理やフォームサニテーションのない基本的なPHPログインスクリプトです。 これは、SQLインジェクションとModSecurityのルールをテストするための例として使用されています。 チュートリアルが終了する前に削除されます。
まず、MySQLプロンプトにアクセスします。
mysql -u root -p
ここで、 sample というMySQLデータベースを作成し、それに接続します。
create database sample; connect sample;
次に、いくつかの資格情報(ユーザー名 sammyとパスワードパスワード)を含むテーブルを作成します。
create table users(username VARCHAR(100),password VARCHAR(100)); insert into users values('sammy','password');
最後に、MySQLプロンプトを終了します。
quit;
次に、Apacheのドキュメントルートにログインスクリプトを作成します。
sudo nano /var/www/html/login.php
次のPHPスクリプトをファイルに貼り付けます。 スクリプトがデータベースに接続できるように、以下のスクリプトのMySQLパスワードを前に設定したものに変更してください。
/var/www/html/login.php
<html> <body> <?php if(isset($_POST['login'])) { $username = $_POST['username']; $password = $_POST['password']; $con = mysqli_connect('localhost','root','your_mysql_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>This is text that should only be displayed when logged in with valid credentials.</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>
このスクリプトはログインフォームを表示します。 ブラウザを開き、http://your_server_ip/login.php
に移動して表示します。 正しいクレデンシャルのペアを入力した場合、たとえば ユーザー名フィールドにsammy、 Password フィールドにパスワード、メッセージが表示されます。これは、有効な資格情報でログインした場合にのみ表示されるテキストです。 ログイン画面に戻って間違ったクレデンシャルを使用すると、無効なユーザー名またはパスワードというメッセージが表示されます。
次の仕事は、ログインページをバイパスするためにSQLインジェクションを試すことです。 ユーザー名フィールドに次のように入力します。
SQLインジェクションのユーザー名
' or true --
このインジェクションが機能するには、--
の後にスペースが必要であることに注意してください。 パスワードフィールドを空のままにして、ログインボタンを押します。 スクリプトは、認証されたユーザー向けのメッセージを表示します。 次のステップでは、これを防ぎます。
ステップ4—ルールを設定する
このステップでは、いくつかのModSecurityルールを設定します。
CRSの有効化
物事を簡単にするために、ModSecurityと一緒にすでにインストールされている多くのルールがあります。 これらはCRS(コアルールセット)と呼ばれ、/usr/share/modsecurity-crs
ディレクトリにあります。 これらのルールをロードするには、これらのディレクトリ内の.conf
ファイルを読み取るようにApacheを設定する必要があるため、security2.conf
ファイルを開いて編集します。
sudo nano /etc/apache2/mods-enabled/security2.conf
ファイルの最後の行(</IfModule>
)の前に、赤で強調表示されている次の2つのディレクティブを追加します。
security2.confを更新しました
IncludeOptional /etc/modsecurity/*.conf IncludeOptional "/usr/share/modsecurity-crs/*.conf" IncludeOptional "/usr/share/modsecurity-crs/activated_rules/*.conf" </IfModule>
ファイルを保存して閉じます。
ディレクトリ/ドメインを除く(オプション)
ModSecurityはSQLクエリをブロックするため、phpMyAdminなどのアプリケーションを実行している場合は、特定のディレクトリまたはドメイン名を除外することが理にかなっている場合があります。 WordPressのようなCMSアプリケーションの管理バックエンドを除外することもお勧めします。 新しいサーバーでこのチュートリアルを実行している場合は、この手順をスキップできます。
完全なVirtualHostのModSecurityを無効にするには、仮想ホストファイルの<VirtualHost>[...]</VirtualHost>
ブロック内に次のディレクティブを配置します。
<IfModule security2_module> SecRuleEngine Off </IfModule>
特定のディレクトリを省略する場合(たとえば、/var/www/wp-admin
):
<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>
SQLインジェクションルールのアクティブ化
次に、SQLインジェクションルールファイルをアクティブ化します。 必要なルールファイルは、Apacheのmods-enabled
ディレクトリと同様のactivated_rules
ディレクトリにシンボリックリンクされている必要があります。 activated_rules
ディレクトリに移動します。
cd /usr/share/modsecurity-crs/activated_rules/
次に、modsecurity_crs_41_sql_injection_attacks.conf
ファイルからシンボリックリンクを作成します。
sudo ln -s ../base_rules/modsecurity_crs_41_sql_injection_attacks.conf .
最後に、ルールを有効にするためにApacheをリロードします。
sudo service apache2 reload
次に、前に作成したログインページを開き、ユーザー名フィールドで同じSQLインジェクションクエリを使用してみます。 手順2でSecRuleEngine
ディレクティブをOn
に変更したため、 403Forbiddenエラーが表示されます。 (SecRuleEngine
がDetectionOnly
オプションのままになっている場合、インジェクションは成功しますが、試行はmodsec_audit.log
ファイルに記録されます。)
このPHPログインスクリプトはModSecurityのテストのみを目的としているため、テストが完了したら削除する必要があります。
sudo rm /var/www/html/login.php
ステップ5—独自のルールを作成する
このセクションでは、スパムに一般的に関連付けられている特定の単語がHTMLフォームに入力された場合に、リクエストをブロックするルールチェーンを作成します。
最初に、テキストボックスから入力を取得してユーザーに表示するサンプルPHPスクリプトを作成します。 form.php
というファイルを開いて編集します。
sudo nano /var/www/html/form.php
次のコードを貼り付けます。
/var/www/html/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ディレクトリに配置したりできます。 ルールをmodsecurity_custom_rules.conf
という別の新しいファイルに配置します。
sudo nano /etc/modsecurity/modsecurity_custom_rules.conf
このファイルに以下を貼り付けます。 ブロックしている2つの単語は、blockedword1とblockedword2です。
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:(blockedword1|blockedword2))"
SecRule
の構文はSecRule VARIABLES OPERATOR [ACTIONS]
です。 ここでは、チェーンアクションを使用して、変数REQUEST_FILENAME
をform.php
と、REQUEST_METHOD
をPOST
と、REQUEST_BODY
を正規表現(@rx)
文字列(blockedword1|blockedword2)
。 ?i:
は、大文字と小文字を区別しない一致を行います。 これら3つのルールすべてが正常に一致すると、ACTION
は拒否し、msg "Spam detected."
でログに記録します。チェーンアクションは、論理積をシミュレートして3つのルールすべてに一致します。
ファイルを保存し、Apacheをリロードします。
sudo service apache2 reload
ブラウザでhttp://your_server_ip/form.php
を開きます。 blockedword1またはblockedword2を含むテキストを入力すると、403ページが表示されます。
このPHPフォームスクリプトはModSecurityのテストのみを目的としているため、テストが完了したら削除する必要があります。
sudo rm /var/www/html/form.php
結論
このチュートリアルでは、ModSecurityをインストールして構成し、カスタムルールを追加する方法を学習しました。 詳細については、公式のModSecurityドキュメントをご覧ください。