前回はこのサイトが不正ログインの攻撃を受けたため不安定になったことを紹介しました。
今回はその対策としてBasic認証を設定します。
Basic認証とは?
Basic認証とはある特定のWebページにアクセスしたときに、ユーザ名とパスワードを入力することを要求する仕組みです。
古い方法なのでいろいろ問題もあるのですが、今回のWordPressログイン連続攻撃は力技なので、Basic認証を設定することでサイトが落ちることを回避することができます。
なぜBasic認証が有効なのか?
今回問題だったのはWordPressのログイン画面(wp-login.php)に高い頻度でアクセスが発生し、そのたびごとにPHP5-FPMが動作してしまい、CPUを消費してしまっていることでした。
ログイン失敗すると一定時間ログインを受け付けなくする「Login Security Solutionプラグイン」などでセキュリティを高めても、PHP5-FPMが動作する回数を抑えなくては、サイトの不安定は解消できません。
一方、Basic認証はWebサーバ(Nginx)が行います。Basic認証を通過したあとに、初めてwp-login.phpが実行されます(PHP5-FPMが動作する)。このため、Basic認証を設けることで、サイトが不安定になることを防ぐことができます。
もちろんWebサーバ(Nginx)には負荷がかかりますが、簡単なBasic認証という方式であることと、Nginxが高負荷に強いWebサーバであることから、問題ないと判断しました。
Nginxの設定
NginxでBasic認証を設定する方法はGoogleで検索すると多数出てきます。
- Nginx でBasic認証(ユーザ名、パスワードを求める )するには
- [nginx] BasicAuthentication – Basic認証を実装するの巻
- 網元でWordPressの管理画面にアクセス制限(IP or Basic認証)をかける時に /etc/nginx/conf.d/default.conf に追記する内容
一見、非常に簡単なようなのですが、私のサイトは
の2点から、ちょっと工夫が必要でした。
なお、私のnginxの設定ファイルは下記で公開しています。
おさらい: ログイン画面/管理画面をSSL対応にする
nginxの設定を変える前にWordPressの設定を見直します。
見直す点はログイン画面と管理画面のセキュリティです。これらの画面では重要な情報をやり取りするので通常のhttpではなくhttps(SSL)で通信するようにしておいたほうが安全です。
https(SSL)を使うためにはWordPressの管理ファイル(wp-config.php)を変更します。詳しくは下記のページを参照してください。
以前はwp-config.phpだけhttpsでアクセスするようにしていたのですが、今回からは管理画面全体をhttpsでアクセスするように変更しました(「define(‘FORCE_SSL_ADMIN’, true)」を追記した)。
これで普通のhttpでWordPressのログイン画面や管理画面にアクセスしても強制的にhttps(SSL)での接続となります。
httpでアクセスするサイトの設定
まず、通常のhttp(ポート80)でのアクセスを受け付けるの設定ファイル(私の場合は/etc/nginx/sites-available/scratchpad-blog)についてです。
このファイルでWordPress関係の処理を記載しているので、このファイルBasic認証のための設定を記載すればよさそうですが・・・実は違います。
上述のようにWordPressの設定でログイン画面・管理画面を強制的にhttps(SSL)で接続するようにしているため、ログイン画面・管理画面に関する処理はこの設定ファイルではなく、httpsでアクセスするサイトの設定ファイルに従うのです。
したがって、特に変更する必要はありません。以前と若干記載を変えたので、再掲しておきます。
### https://scratchpad.jp の設定 # nginxのproxy cacheの設定 proxy_cache_path /var/cache/nginx/scratchpad.jp levels=1:2 keys_zone=scratchpad.jp:64m inactive=1d max_size=768m; proxy_cache scratchpad.jp; proxy_cache_valid 200 302 60m; # 正常時のキャッシュ有効時間は60分 ##proxy_cache_valid 404 10m; # 404エラーのキャッシュ有効時間は10分 include proxy_params; # 共通設定は/etc/nginx/proxy_paramsに記載 # フロントエンドの設定 server { # scratchpad.jpに対するポート80への接続を処理する listen 80; server_name scratchpad.jp *.scratchpad.jp; root /www/scratchpad.jp; index index.php; # ログファイルの設定 エラーは警告レベル以上を記録 access_log /var/log/nginx/scratchpad-front-access.log combined; error_log /var/log/nginx/scratchpad-front-error.log warn; # proxy cacheを有効にする include global/wordpress-proxy-cache.conf; }
httpsでアクセスするサイトの設定
次にhttps(SSL)でアクセスするサイト側を設定します。
上述したようにWordPressのログイン画面と管理画面をhttps(SSL)でアクセスするので、Basic認証の設定はこちらのファイルで行います。
また、https(SSL)で通常公開しているサイトにアクセスがあった場合は、強制的にhttpで公開するようにします。例えば、https://scratchpad.jp/にアクセスがあった場合はhttp:/scratchpad.jp/で公開するようにします。
これはhttpでアクセスした場合は、nginxのプロキシ・キャッシュ機能が効き効率が良いことと、外部からのリンクがhttpsとhttpで分散しないようにhttpで統一するためです。
上記を考慮してhttpsでアクセスするサイトの設定ファイル(私の場合は/etc/nginx/site-available/scratchpad-blog-ssl)を修正します。
# httpsでの接続時の設定 (WordPressの管理者用画面など) server { # scratchpad.jpに対するポート443への接続を処理する listen 443; server_name scratchpad.jp; root /www/scratchpad.jp; index index.php; # ログファイルの設定 エラーは警告レベル以上を記録 access_log /var/log/nginx/scratchpad-ssl-access.log combined; error_log /var/log/nginx/scratchpad-ssl-error.log warn; # SSLを有効にする ssl on; ssl_certificate /etc/ssl/certs/scratchpad.jp.crt; ssl_certificate_key /etc/ssl/private/scratchpad.jp.key; # 安全のためBasic認証 location ~* /wp-login\.php|/wp-admin/(^admin-ajax\.php) { auth_basic "Administrator Login"; auth_basic_user_file "/etc/nginx/.htpasswd"; # Basic認証通過したら普通にPHPを呼び出し include global/exec_php.conf; break; } ## basic認証不要な領域 # 通常のページはhttpにリダイレクト location ~* ^/$|^/index|^/20[0-9][0-9]/|^/summary/|^/category/|^/tag/|^/about/ { rewrite ^(.*) https://scratchpad.jp$1 permanent; break; } # 共通の制限事項を設定 include global/restrictions.conf; # マルチサイト用WordPressの設定を有効にする include global/wordpress-ms.conf; }
20~28行目の記述がBasic認証のための記述です。アクセスしたURLにwp-login.phpかwp-admin/admin-ajax.phpが含まれているときにはBasic認証を要求します。
Basic認証のためのユーザ名とパスワードを記載したファイルは「/etc/nginx/.htpasswd」となります(作り方は後述)。
26行目は重要です。20行目で指定した条件で引っかかったアクセス(wp-login.phpとwp-admin関連)をどのように処理するかを記載します。ここでは処理内容は別ファイルのexec_php.conf(後述)に記載して、それを読み込むことにしています。このように処理内容を記述しておかないと、wp-login.phpにアクセスしてBasic認証に成功しても、ブラウザがwp-login.phpファイルをダウンロードしてしまい、期待した動作になりません。
ここでインクルードしているexec_php.confは
# ファイルが存在しない場合は404エラー # 参照: http://forum.nginx.org/read.php?2,88845,page=3 try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_send_timeout 5m; fastcgi_read_timeout 5m; fastcgi_connect_timeout 5m; include fastcgi_params; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass php_backend; # Nginx Cache Controllerプラグインに必要 fastcgi_pass_header "X-Accel-Expires";
となっています。
30~35行目は、httpsでのアクセスをhttpに書き換える処理です。URLのホスト名以降が37行目の条件式にマッチした場合には強引にhttpでアクセスするようにリダイレクトします。ここでは次の条件のいずれかを満たした場合にこの条件式にマッチします。
- 「^/$」: 「/」だけ。すなわちhttps://scratchpad.jp/が該当。
- 「^/index」:「/index」で始まる場合。https://scratchpad.jp/index.phpやhttps://scratchpad.jp/index.htmlが該当。
- 「^/20[0-9][0-9]/」:「/2013」など数字4桁で始まる場合。本ブログの各記事のパーマリンクが該当。
- 「^/summary/」:「/summary/」で始まる場合。https://scratchpad.jp/summary/が該当。
- 「^/category/」:「/category/」で始まる場合。https://scratchpad.jp/category/が該当。
- 「^/tag/」:「/tag/」で始まる場合。https://scratchpad.jp/tag/が該当。
- 「^/about/」:「/about/」で始まる場合。https://scratchpad.jp/about/が該当。
なおrestrictions.confとwordpress-ms.confについては下記を参照してください。
認証ファイル(.htpasswd)の作成
Basic認証の設定ファイルはhtpasswdコマンドで作成できます。このコマンドはapache2-utilsパッケージに含まれますので、まずはダウンロードします。
apt-get install apache2-utils
そして次のコマンドを実行して、設定したいパスワードを2回入力すると.htpasswdファイルができます。
htpasswd –c /etc/nginx/.htpasswd ユーザ名
動作確認
それでは動作確認をします。まずはnginxを再起動します。
service nginx restart
続いてログイン画面にアクセスします。httpsになっているか確認するために、あえて通常のhttpでログイン画面(http://ブログのURL/wp-login.php)にアクセスしてみましょう。
WordPressの設定ファイルが正しく設定されていれば、自動的にhttps://ブログのURL/wp-login.phpに飛ばされるはずです。なお、サーバの証明書が自己証明(オレオレ証明)である場合は、httpsでアクセスした際に証明書に関する警告が表示されます。
そして次のようなユーザ名とパスワードを入力するためのダイアログボックスが表示されればひとまずOKです。
ここでhtpasswdコマンドで指定したユーザ名とパスワードを入力してちゃんとWordPressの管理画面(ダッシュボード)が表示されれば完了です。
ブラウザがwp-login.phpというファイルをダウンロードしてしまったら、上記のscratchpad-blog-sslの26行目に相当する記述(PHP-FPMを実行するための記述)があるかどうか確認してください。
ログの確認
最後にログを確認してみます。設定ファイルのaccess_logで指定したファイルを確認してみましょう。
ログインに成功すると次のようなログが残っているはずです。aaa.bbb.ccc.dddは自分のIPアドレスです。
1行目がwp-login.phpにアクセスした際のログで、2行目がユーザ名/パスワードを入力してBasic認証に成功した際のログです。
aaa.bbb.ccc.ddd - - [07/Sep/2013:15:08:42 +0900] "GET /wp-login.php HTTP/1.1" 401 596 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36" aaa.bbb.ccc.ddd - ユーザ名 [07/Sep/2013:15:08:55 +0900] "GET /wp-login.php HTTP/1.1" 200 1219 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
またerror_logで指定したファイルをしばらく監視してみましょう。時々次のようなログがあるはずです。
YYYY/MM/DD HH:MM:SS [error] 46811#0: *31503 no user/password was provided for basic authentication, client: eee.fff.ggg.hhh, server: scratchpad.jp, request: "GET /wp-login.php HTTP/1.1", host: "scratchpad.jp"
このログはIPアドレスeee.fff.ggg.hhhのユーザがwp-login.phpにアクセスしたものの、Basic認証に失敗したことを(=wp-login.phpに対する不正アクセスを事前にブロックしたこと)を示しています。
まとめ
今回はWordPressのログイン画面と管理画面にBasic認証を設定して、wp-login.phpに対する連続不正ログイン攻撃を防ぐ方法を紹介しました。
簡易的な方法ではありますが、現在のwp-login.phpへの攻撃を食い止めるには絶大な効果がありますので、設定しておいて損はないと思います。
Basic認証を追加した後は、私のサイトでは急激にロードアベレージが上がるということはなくなりました。
次回はWordPressで発生した問題を引き続き紹介します。
コメント