「広告」

ワードプレス、ハッキング対策!これだけは行うべし!

「広告」
記事内に広告が含まれています。
「広告」

ワードプレスは、広く利用されているソフトウェアです。
そのため、脆弱性も、容易に手に入れることができます。

ワードプレスがハッキングされた。というのは、新聞などのメディアには乗らないですが、
それなりに、被害を受けているサイトがあるかと思います。

被害を防ぐには

ログインユーザを隠す
パスワードを複雑なものにする
ログインする場所を防御をする

というのが有効な手段かと思います。

「広告」

ワードプレスのログを見ると・・・

まずは、実際のログを見てみますと・・・

XXX.XXX.XXX.XXX - - [XX/Aug/2020:01:45:16 +0900] "GET / HTTP/1.1"
XXX.XXX.XXX.XXX - - [XX/Aug/2020:01:45:16 +0900] "GET /wp-includes/wlwmanifest.xml HTTP/1.1"
XXX.XXX.XXX.XXX - - [XX/Aug/2020:01:45:16 +0900] "GET /?author=1 HTTP/1.1"
XXX.XXX.XXX.XXX - - [XX/Aug/2020:01:45:17 +0900] "GET /?author=2 HTTP/1.1"
XXX.XXX.XXX.XXX - - [XX/Aug/2020:01:45:17 +0900] "GET /wp-json/wp/v2/users/ HTTP/1.1"
XXX.XXX.XXX.XXX - - [XX/Aug/2020:01:45:18 +0900] "GET /wp-json/oembed/1.0/embed?url=https://(FQDN)/ HTTP/1.1"
XXX.XXX.XXX.XXX - - [XX/Aug/2020:01:45:18 +0900] "POST /xmlrpc.php HTTP/1.1"

というアクセスがありました。悪意のありそうなサーバーから、連続的にアクセスしています。

「wp-includes/wlwmanifest.xml 」は、ワードプレスプラグインの「Windows Live Writer」から情報を取得しようとしているようです。

「author=1」「author=2」は、ログインユーザ名を取得を試みています。

「/wp-json/wp/v2/users/」「/wp-json/oembed/1.0/embed」も同様にユーザ名の取得を試みています。

そして、取得した情報から、最終的に、「xmlrpc.php」にアクセスをして、ログインを試みます。
ログインに成功すると、サイトの改ざんなどが行われるかもしれません。

この手法が、すべてではなく、悪意のあるサーバーは、あらゆる手段を駆使して、ユーザとパスワードを盗もうとします。

「広告」

ハッキングに必要な情報は・・

ハッキングに必要な情報は、
「ログインユーザ」
「ログインパスワード」
「ログインをする場所」
です。

それぞれ、脆弱性対策を行いましょう。

「広告」

ログインユーザを隠蔽

ワードプレスにログインする場合、任意のユーザ名が設定されています。
この「ユーザ名」ですが、「私しかしらない」ということはありません。

何も対策をとっていない場合は、簡単に入手できます。

author情報

https://(FQDN)/?author=1

で、情報を取得できます。

# wget https://(FQDN)/?author=1

(略)
--2020-XX-XX XX:XX:XX-- https://(FQDN)/author/adminuser/
(略)

と出力されます。上記の「auther」の後の英数字「adminuser」が、ログインユーザ名です。

xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:29:54 +0900] "GET /?author=1 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:29:58 +0900] "GET /?author=2 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:01 +0900] "GET /?author=3 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:03 +0900] "GET /?author=4 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:07 +0900] "GET /?author=5 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:09 +0900] "GET /?author=6 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:10 +0900] "GET /?author=7 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:14 +0900] "GET /?author=8 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:15 +0900] "GET /?author=9 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:19 +0900] "GET /?author=10 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:20 +0900] "GET /?author=11 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:23 +0900] "GET /?author=12 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:27 +0900] "GET /?author=13 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:28 +0900] "GET /?author=14 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:30 +0900] "GET /?author=15 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:32 +0900] "GET /?author=16 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:34 +0900] "GET /?author=17 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:36 +0900] "GET /?author=18 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:38 +0900] "GET /?author=19 HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:08:30:40 +0900] "GET /?author=20 HTTP/1.1"

↑実際のログです。ある悪意のあるサーバーから、「ログインユーザ」を検索しています。

ログインユーザがわかれば、今度は、パスワードで、ログインを試みます。

このログインユーザを「隠蔽」するには・・・

↑ワードプレスプラグイン「Edit Author Slug」で設定をします。

まずは、

--2020-XX-XX XX:XX:XX-- https://(FQDN)/author/adminuser/

の「author」を変更します。

↑「Edit Author Slug」導入後、「設定」から、「Edit Author Slug」を選びます。

↑上記の「author」のところを、任意の英数字に変更します。

--2020-XX-XX XX:XX:XX-- https://(FQDN)/xxxx/adminuser/

↑上記の「xxxx」の部分が変更となります。

次に

--2020-XX-XX XX:XX:XX-- https://(FQDN)/author/adminuser/

↑の「adminuser」を変更します。

↑「ユーザ一覧」を選ぶと、右側に「投稿者スラッグ」という列が出てきます。
「編集」を選びます。

↑画面下に、「Edit Author Slug」というブロックがあり、「投稿者スラッグ」として、4つ選ぶ事ができます。今回、3つめの任意の英数字を選択します。

↑保存をして、「ユーザ一覧」に戻ると、「投稿者スラッグ」の列に、任意の英数が設定されています。

--2020-XX-XX XX:XX:XX-- https://(FQDN)/list/576sdfadfbn8fc346a2eadfa78/

↑と変更されました。
実際のログインユーザは、元のユーザ名であり、従来通りのログイン名で、入ることができます。

公開前に、このプラグインを設定すればいいのですが、
公開後に、プラグインを導入した場合は、「ログインユーザ」は、既に検索されている可能性もあります。
この場合、「ログインユーザ」を変更しましょう。

「REST API」でユーザ名取得

「REST API」

# wget https://(FQDN)/wp-json/wp/v2/users/

↑上記のURLをたたくと、ログインユーザを取得できます。

これは、「REST API」といって、wordpress標準の機能です。
「Contact Form 7」などでも利用されています。

単純に、「REST API」を止めてしまうと、「Contact Form 7」が機能しなくなります。

この場合、function.phpに、以下のソースを入れると、脆弱性が少なくなります。

add_filter( 'rest_endpoints', function( $endpoints ){
  if ( isset( $endpoints['/wp/v2/posts'] ) ) {
    unset( $endpoints['/wp/v2'] );
  }
  if ( isset( $endpoints['/wp/v2/posts'] ) ) {
    unset( $endpoints['/wp/v2/posts'] );
  }
  if ( isset( $endpoints['/wp/v2/posts'] ) ) {
    unset( $endpoints['/wp/v2/posts'] );
  }
  if ( isset( $endpoints['/wp/v2/posts/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/posts/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/posts/(?P<parent>[\d]+)/revisions'] ) ) {
    unset( $endpoints['/wp/v2/posts/(?P<parent>[\d]+)/revisions'] );
  }
  if ( isset( $endpoints['/wp/v2/posts/(?P<parent>[\d]+)/revisions/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/posts/(?P<parent>[\d]+)/revisions/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/pages'] ) ) {
    unset( $endpoints['/wp/v2/pages'] );
  }
  if ( isset( $endpoints['/wp/v2/pages/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/pages/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/pages/(?P<parent>[\d]+)/revisions'] ) ) {
    unset( $endpoints['/wp/v2/pages/(?P<parent>[\d]+)/revisions'] );
  }
  if ( isset( $endpoints['/wp/v2/pages/(?P<parent>[\d]+)/revisions/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/pages/(?P<parent>[\d]+)/revisions/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/media'] ) ) {
    unset( $endpoints['/wp/v2/media'] );
  }
  if ( isset( $endpoints['/wp/v2/media/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/media/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/types'] ) ) {
    unset( $endpoints['/wp/v2/types'] );
  }
  if ( isset( $endpoints['/wp/v2/types/(?P<type>[\w-]+)'] ) ) {
    unset( $endpoints['/wp/v2/types/(?P<type>[\w-]+)types'] );
  }
  if ( isset( $endpoints['/wp/v2/statuses'] ) ) {
    unset( $endpoints['/wp/v2/statuses'] );
  }
  if ( isset( $endpoints['/wp/v2/statuses/(?P<status>[\w-]+)'] ) ) {
    unset( $endpoints['/wp/v2/statuses/(?P<status>[\w-]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/taxonomies'] ) ) {
    unset( $endpoints['/wp/v2/taxonomies'] );
  }
  if ( isset( $endpoints['/wp/v2/taxonomies/(?P<taxonomy>[\w-]+)'] ) ) {
    unset( $endpoints['/wp/v2/taxonomies/(?P<taxonomy>[\w-]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/categories'] ) ) {
    unset( $endpoints['/wp/v2/categories'] );
  }
  if ( isset( $endpoints['/wp/v2/categories/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/categories/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/tags'] ) ) {
    unset( $endpoints['/wp/v2/tags'] );
  }
  if ( isset( $endpoints['/wp/v2/tags/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/tags/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/users'] ) ) {
    unset( $endpoints['/wp/v2/users'] );
  }
  if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/users/me'] ) ) {
    unset( $endpoints['/wp/v2/users/me'] );
  }
  if ( isset( $endpoints['/wp/v2/comments'] ) ) {
    unset( $endpoints['/wp/v2/comments'] );
  }
  if ( isset( $endpoints['/wp/v2/comments/(?P<id>[\d]+)'] ) ) {
    unset( $endpoints['/wp/v2/comments/(?P<id>[\d]+)'] );
  }
  if ( isset( $endpoints['/wp/v2/settings'] ) ) {
    unset( $endpoints['/wp/v2/settings'] );
  }
  return $endpoints;
});

出典元:
Turn off WordPress’s default endpoint.

これで、「404エラー(not found)」のエラーを返します。

feed情報

昔から、使われている「feed情報」

https://(FQDN)/feed/

で、アクセスをすると、

↑「creator」というところに、ログインユーザ名が表示されます。(上記は、対応済み)

これを変更するには、ワードプレスのログインユーザにおいて、

↑「ニックネーム」「ブログ上の表示名」を、ログインユーザでないものに変更をします。

インターネット上を検索すると、「feed」自体を無効にするアドバイスがありますが、google botなど、検索エンジンからfeedへのアクセスもあり、feed自体を無効にしてしまうと、SEOに悪影響があると考えています。

feedの機能は、有効にしつつ、脆弱性を高めるのは、上記の「ニックネーム」の変更がよいのではないかと思います。

「広告」

ログインする場所を防御をする

XML-RPCを防御

ワードプレスでは、「xmlrpc」(XML-RPC)という、ワードプレスに、外部から、投稿ができるプロトコルが標準装備されています。

pingbackなどにも利用されていますが、今は、一般的ではないかと思います。

悪意のある外部のサーバーから
https://(FQDN)/xmlrpc.php
にアクセスをして、IDとパスワードで、総当たり攻撃(ブルートフォース攻撃)や、リスト攻撃で、パスワードを調べます。

xxx.xxx.xxx.xxx - - [XX/Aug/2020:17:16:57 +0900] "POST /xmlrpc.php HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:17:41:01 +0900] "POST /xmlrpc.php HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:18:04:53 +0900] "POST /xmlrpc.php HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:18:28:15 +0900] "POST /xmlrpc.php HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:18:52:06 +0900] "POST /xmlrpc.php HTTP/1.1"
xxx.xxx.xxx.xxx - - [XX/Aug/2020:19:14:02 +0900] "POST /xmlrpc.php HTTP/1.1"

↑と、パスワードを入手しようとするサーバーからのログが記録されています。

この「xmlrpc.php」を「アクセス不可」にすることで、脆弱性対策となります。

これは、様々な方法があります。

nginxでアクセス不可
apacheでアクセス不可
ワードプレスプラグイン、SiteGuardで、アクセス不可

nginxでアクセス不可

location = /xmlrpc.php {
        deny all;
}

と、設定をします。

apacheでアクセス不可

<Files "xmlrpc.php">
    Require all denied
</Files>

と、設定をします。

ここで、パスワードが判明すると、「XML-RPC」の機能で任意のコンテンツを投稿されてしまうかもしれません。

ワードプレスプラグイン、SiteGuardで、アクセス不可

↑「XMLRPC無効化」を選びます。

そのほか、.htaccessでの制御なども可能です。(SiteGuardは、.htaccessを利用しています)

不可にすると、本来の機能が失われますので、ご留意ください。

wp-login.phpを防御

ログインする場所は、デフォルトでは、

https://(FQDN)/wp-login.php
です。

今回、SiteGuardプラグインで、防御をしてみます。

↑上記の

1)ログインページ変更
2)画像認証
3)ログインロック

を、設定してみましょう。

そのほか、IP制限、基本認証なども、有効な手段かと思います。

「広告」

その他、OS,phpなどのソフトウェアも・・・

当然ながら、周辺ソフトウェア、apache,nginix,phpやOSのアップデートも、重要です。

「広告」

ワードプレス脆弱対策

ワードプレスを含めて、100%の脆弱性対策はできないですが、できる限り100%に近づけたいですね。バージョンアップをすると、逆にハッキングされやすくなったりして・・・

自分におごらず、あらゆる情報をインプットして、対策を取りたいです。

「広告」

関連記事

ワードプレス SiteGuard 画像表示されない

お勧めプラグイン「SiteGuard WP Plugin」で「画像ファイル、書き込み失敗」

タイトルとURLをコピーしました