何が問題か
WordPress では、
- WordPressサイトのURL/?author=数字
にアクセスすることで、
- WordPressサイトのURL/author/ユーザ名
に自動転送される仕組みになっています。
これを悪用すれば、
これを悪用すれば、
- WordPress のユーザー名に割り当てられている「すべての」ユーザー名(ログインID)を知られてしまいます。
このことは
にあるように脆弱性診断システムなどで脆弱性ありと判断される場合があります。
対策しているかどうかの確認方法
コマンドラインツール curl を使えば(macOS には標準搭載)、たとえば、 http://example.com に WordPressのサイトがあるとすると
- curl -v -D - "http://example.com/?author=1"
と Mac ならターミナルから入力することで、標準出力にヘッダー情報が出てきます。
そこの location: をみると
そこの location: をみると
- location: http://example.com/author/ユーザー名/
になってユーザー名が見えてしまっています。これが存在しない場合、ユーザー名でない場合には何らかの対策がされているということになります。
実際にウェブサーバーログをみると、
?author=1
?author=1
?author=2
?author=3
?author=4
...
など大量にスキャン(ポーリング)されているサイトもありました。
ユーザー名が漏洩したからといって即座に問題になるとは限らない
先に説明しておきますが、ログインのユーザー名が漏洩したからといって、それだけで不正ログインされるわけではありません。一般的にはパスワードが必要だからです。しかしながら、他のサイトとパスワードを同一(パスワードの使いまわし)をされていれば、もし他のサイトからパスワードが漏洩してしまうとログインできてしまいます。ですので別途ログインについては、下記のようなセキュリティ対策を施しておくのがよいです。
- IPアドレス制限
- 認証にクラウドサービス(Google認証等)をつかう
- 総当り攻撃(ブルートフォース攻撃)への対策(一度に大量アクセスを防止)
などです。そうすれば、たとえユーザー名が漏洩したとしても問題はなくなります。
とはいえ、WordPress にどのユーザーがログインできているのか知られることは嫌ですよね。ですので対策したほうがよいでしょう。
ここでは
1. ウェブシステム側で止める
2. WordPress プラグインで止める(自作)
に絞って備忘録として残しておきます。
対策1. ウェブシステム側で止める
各ウェブサイトの設定において、先頭から
- /?author=*** = 404エラーとする
- /author/*** = トップページへリダイレクトする
これが可能なら、WordPress に到達する前に止めることができるのでウェブサイトへの負荷が減ります。
/author/** のケースは、 /hogehoge/author/** を除外するかどうかが、ややこしくなります。たとえばカテゴリー名に使った場合とかです。とはいえ、author は予約語でもあるので、まぁそこは除外するでよいでしょう。
/author/** のケースは、 /hogehoge/author/** を除外するかどうかが、ややこしくなります。たとえばカテゴリー名に使った場合とかです。とはいえ、author は予約語でもあるので、まぁそこは除外するでよいでしょう。
Apache での設定方法
WordPress側では、RewriteBase が設定されているはずなので
- RewriteRule ^\?author=(.*)? / [NC,R=404,L]
- RewriteRule ^author/(.*)? / [R=302,L]
管理者画面側では、?hogehoge=**&author=**
となるので、管理者画面では除外できるはずです(未検証)。
うまくいかなければ、RewriteCond ルールなどを併用すればいいでしょう。筆者は NGINX しかほぼ触っていないので、詳細は
- [WordPress] /?author=xx をちゃんと阻止した話(Qiita)
- mod_rewriteで、存在しないファイルへのリクエストに404を返す(Qiita)
- Feature request: Block Author URLs (WordPress.org forum)
などを参考にしてみてください。
NGINX での設定
nginx は if 文など条件を入れ子構造にできないという問題があります。
したがって細かな条件を書くのが超大変です。
ここではドメインやサブドメイン直下(http://example.com やhttp://hogehoge.example.com/) のように http://example.com/hogehoge というサブディレクトリに保存されていないと仮定すると、汎用性がある設定としては、
set $rp_flag flag;
set $rp_flag2 flag;
if ($request_uri ~ "^/wp-admin/"){
set $rp_flag false;
}
if ($request_uri ~ "^/author/"){
set $rp_flag2 "${rp_flag2}_true";
}
if ($args ~ "author=(.*)"){
set $rp_flag "${rp_flag}_true";
}
if ($rp_flag = flag_true){
return 404;
}
if ($rp_flag2 = flag_true){
return 302 /;
}
上記コードでは、
1. /wp-admin/ (管理画面)は対象外(リダイレクトしない)
*つまり公開している側のみリダイレクトする
*つまり公開している側のみリダイレクトする
2. /author/ か GETパラメーターに author= があるかのいずれか
上記をすべて満たす場合に、トップページへリダイレクトする
ということになります。
「1」が必要な理由は、管理画面の投稿や固定ページ等で各ユーザーごとに一覧を表示するのに、author パラメーターが使われているためです。それは必要だろうという判断です。
このように、フラグを文字連結させた上で、それを文字判定させる手法になります。
さらに、requiest_uri に ? があるとパラメータ扱いになって、$args に保存されるという仕様もあってなおややこしい。
参考:
- Nginxで複数条件のIF文を書く方法がすごいw(Qiita)
- nginx の rewrite で クエスチョンマークがある時(プログラマー社長の「日々発見」)
対策2. WordPress プラグインで止める(自作)
- Disable Author Archive Redirection(WordPress 公式プラグインとして登録)
ウェブサーバーのほうで止めることができない場合(設定をいじれない)もあると思います。その場合には、テーマの functions.php に書くなどの方法もありますが、サイトが大量にあるとやってられません。
公式プラグインだと WP-CLIコマンドなどで一括インストールが可能になるので、その設定をしていれば、
- wp @all plugin install プラグイン名 --activate
幸い筆者は WordPress の公式プラグインをいくつかアップして、メンテナンスしているのでそのあたりのやり方は知ってます。
ただ問題はどのような手法で止めるのかがかなり悩みました。
- WordPressのknockout_author_queryを止めたらサイト速度が50msも改善された件について(riscascape.net)
- いい加減 flush_rewrite_rules を書くのはやめてください!!(Toro_Unit)
- Stop User Enumeration in WordPress (perishablepress.com)
- 管理画面以外(公開されている部分のみ)に適用
- QUERY_STRING に「author」項目がある = 404エラー
- REQUEST_URI に /author/ があること = トップへリダイレクト
- redirect_canonical にも対応し、自動補正時にもチェックが走るようにする
という感じです。
2020年3月11日 @kimipooh