この度、私が使っているお名前.com VPS がここ数週間、障害に見舞われ数時間停止してしまいます。
毎回、サーバーを再起動して運用しておりました。
お名前.comのVPSについては、以下をご覧ください。
さて、障害発生時のお名前.comのコントロールパネルから見たリソース情報は以下の通りです。
Disk I/Oが異様に高くなっていることが分かります。
ここ1週間のリソース情報は次の通りです。
時々、Disk I/Oが異常に高くなっているのが分かりますが、これが障害が発生したタイミングです。
障害発生時には、Uptimer Robotからの監視メールが送られるようになっており、メールで異常を発見しサーバーを再起動していました。
Uptimer Robotについては、以下をご覧ください。
今回、この障害の原因を調査して対策を行いました。
目次
nginxのアクセスログから原因を調査する xmlrpc.phpが攻撃対象
サーバー運用での基本は「エラー・障害原因をログから調査する」です。
nginxのアクセスログを調べてみます。
すると、以下のように、xmlrpc.phpにPOSTする行が大量に吐かれていることを見つけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
80.82.65.206 - - [20/Oct/2015:18:52:00 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:00 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:00 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:00 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:01 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:01 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:01 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:02 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:02 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:02 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:02 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:03 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:03 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" 80.82.65.206 - - [20/Oct/2015:18:52:03 +0900] "POST /xmlrpc.php HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)" "-" |
それこそ、1秒に3回ぐらい発行されています。
これは典型的なDDOS攻撃です。
以下は、Wikipediaからの引用です。
DoS攻撃(ドスこうげき、ディーオーエスこうげき、Denial of Service attack)とは、サーバなどのネットワークを構成する機器に対して攻撃を行い、サービスの提供を不能な状態にする攻撃をいう。 サービス妨害攻撃などとも呼ばれる。ゾンビコンピュータを利用した分散型で行う場合は、DDoS攻撃(ディードス攻撃)と呼ばれる。
DDoS攻撃(ディードスこうげき、ディーディーオーエスこうげき、Distributed Denial of Service attack)とは、踏み台と呼ばれる多数のコンピュータが、標的とされたサーバなどに対して攻撃を行うことである。別名として、協調分散型DoS攻撃、分散型サービス妨害攻撃などがある。
単一のホスト(通信相手)からの攻撃ならばそのホストとの通信を拒否すればよいが、数千・数万のホストからでは個々に対応することが難しい。したがって、通常のDoS攻撃よりも防御が困難であり、攻撃による被害はDoS攻撃よりも大きくなると考えられる。攻撃を受けたサーバには踏み台となったコンピュータが攻撃主として認識される。
(wikipediaより)
WordPressのxmlrpc.phpをdeny allにすると、403(Forbidden)
WordPressのxmlrpc.phpというファイルは、外部エディタを使ってブログに書き込んだりするために使われるファイルです。
そのため、Windows Live WriterとかMarsEditのような外部エディタを使っていない人には、このファイルは関係ありません。
そこで、nginx.confから呼ばれるconfファイルに以下の設定を行い、再起動してみます。
1 2 3 4 5 |
location = /xmlrpc.php { deny all; access_log off; error_log off; } |
こうすれば、DDOS攻撃は回避されます。
ちなみに、access_log offとerror_log offを入れておかないと、下記のように大量の403(Forbidden)がログが吐かれてしまいます。
(注意 2015/10/29)
上記のように設定すると /etc/nginx に off というファイルが作成されて、大量のアクセスログが生成されてしまいました。
そこで以下のように変更しました。access_log /dev/null;
error_log /dev/null;
1 2 |
185.93.185.100 - - [23/Oct/2015:16:30:14 +0900] "POST /xmlrpc.php HTTP/1.1" 403 168 "-" "-" "-" 185.93.185.100 - - [23/Oct/2015:16:30:14 +0900] "POST /xmlrpc.php HTTP/1.1" 403 168 "-" "-" "-" |
対策が万全であれば、access_log offとerror_log offを入れておくことがよいです。
ところで、この設定だと、Windows Live Writerが使えません。
Windows Live Writerでブログに投稿しようとすると、以下のメッセージが表示されます。
ログイン中に予期しないエラーが発生しました。
サーバーエラー - 以下のWebアドレスについてサーバーエラーが発生しました。http://xxx/xmlrpc.php
403 Forbidden
まぁ当然ですね。これだと不便です。
allowでIPを許可してみると405 Not Allowed
そこで、confファイルを以下のように変更します。
1 2 3 4 5 6 7 |
location = /xmlrpc.php { allow (自分のグローバルIP); allow 127.0.0.1; deny all; access_log off; error_log off; } |
Apacheと異なり、nginxでは上記のように許可するIPアドレスを先にallowで指定して、その後で、deny allします。
deny allを先に書いて、後でallowを行うと、deny allの方が優先されてしまい、すべてdenyとなってしまいます。
上記の設定を行い、Windows Live Writerで投稿しようとすると以下のようなメッセージが表示されます。
ログイン中に予期しないエラーが発生しました。
サーバーエラー - 以下のWebアドレスについてサーバーエラーが発生しました。http://xxx/xmlrpc.php405 Not Allowed
うーん。。。そこで、今度は以下のように405を200に変更してみました。
1 2 3 4 5 6 7 8 |
location = /xmlrpc.php { allow (自分のグローバルIP); allow 127.0.0.1; deny all; access_log off; error_log off; error_page 405 =200 $uri; } |
すると以下のメッセージが表示されました。
ログイン中に予期しないエラーが発生しました。
サーバーの応答が無効です - ブログサーバーから受信した
blogger.getUsersBlogs メソッドへの応答が無効です。Invalid response document returned from XmlRpc server
このアプローチではダメなので別の方法を探します。
proxy_passでバックエンドに転送すると500 Internal Server Error
そこで、confファイルを以下のように変更します。
proxy_passを使ってバックエンドのfactcgiに転送します。
1 2 3 4 5 6 7 8 |
location = /xmlrpc.php { allow (自分のグローバルIP); allow 127.0.0.1; deny all; access_log off; error_log off; proxy_pass http://127.0.0.1/xmlrpc.php; } |
この設定で、Windows Live Writerを使ってブログに投稿してみると、
500 Internal Server Error
となりました。
ログを表示する設定に変更して、エラーログを見てみました。
1 2 3 4 |
2015/10/23 11:41:44 [crit] 1608#0: accept4() failed (24: Too many open files) 2015/10/23 11:41:44 [crit] 1608#0: accept4() failed (24: Too many open files) 2015/10/23 11:41:45 [alert] 1608#0: *2102 socket() failed (24: Too many open files) while connecting to upstream, client: 127.0.0.1, server: , request: "POST /xmlrpc.php HTTP/1.0", upstream: "http://127.0.0.1:80/xmlrpc.php", host: "127.0.0.1" 2015/10/23 11:44:20 [alert] 1717#0: *1015 socket() failed (24: Too many open files) while connecting to upstream, client: 127.0.0.1, server: , request: "POST /xmlrpc.php HTTP/1.0", upstream: "http://127.0.0.1:80/xmlrpc.php", host: "127.0.0.1" |
Too many open files ?
ファイルディスクリプタが足りない?っていうことでしょうか。
ファイルディスクリプタを増やしてみても502 Bad Gateway
そこで、以下の設定を行います。
/etc/security/limits.confを編集します。最後の行の一つ手前に以下の行を追加します。
1 2 |
* soft nofile 16384 * hard nofile 32768 |
この設定を行うことにより、システムのファイルディスクリプタの上限値、ulimit -nで表示される値を変更します。
設定を変更後、exitとしてから再度、ログインするか、または、su -すると変更が反映されます。
ついでに/etc/nginx/nginx.confの以下の行の値を変更しておきます。
1 2 3 4 5 6 7 |
worker_processes 4; worker_rlimit_nofile 32768; events { worker_connections 4096; } |
この後、nginxを再起動します。
この設定で、Windows Live Writerを使ってブログに投稿してみると、以下のエラーが表示されました。
ログイン中に予期しないエラーが発生しました。
サーバーエラー - 以下のWebアドレスについてサーバーエラーが発生しました。
http://xxx/xmlrpc.php502 Bad Gateway
ログを表示する設定に変更して、エラーログを見てみると以下のように表示されていました。
1 2 |
2015/10/23 17:25:39 [alert] 8386#0: 4096 worker_connections are not enough 2015/10/23 17:25:39 [error] 8386#0: *10182 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 127.0.0.1, server: , request: "POST /xmlrpc.php HTTP/1.0", upstream: "http://127.0.0.1:80/xmlrpc.php", host: "127.0.0.1" |
4096 worker_connections are not enough
さすがにこのエラーは違うだろう。。。
まとめ
nginxでWordPressを使っていて、xmlrpc.phpを自分のアクセス元だけ許可するっていう設定なら、どこでもありそうなんですが、同じ悩みを持っている人いませんか。
ちょっと困っています。
現在、Windows Live Writerが使えなくて不便しています。
引き続き調査します。
WordPressのおすすめ本
↓WordPressのおすすめ本はコチラ
コメント
[…] WordPressでxmlrpc.phpのDDOS攻撃を回避する nginxでPOSTメソッド対策 この度、私が… […]