WordPress のセキュリティ対策・III (rev.2)
2009-12-01 23:34 /
WordPress のセキュリティ対策について、再検討します。前編・後編を公開してから約1年の時間が経って WordPress 自体に改良も加わっていますし、前回の記事で取り上げた対策に「誤りではないか」と指摘できるものがあるかもしれないので、このテーマは少しずつフォローしていきたいと思います。
「WordPress のセキュリティ対策・前編」、「WordPress のセキュリティ対策・後編」では、以下のような対策をご紹介しました。
- ブログシステムが必要かどうか判断すること
- 適正なレンタルサーバを選定すること
- 利用する機能を選ぶこと
- インストール後の設定を確認すること
- セキュリティ対策用のプラグインを導入すること
- 適正なレンタルサーバを選定すること(続)
- テーブル名の接頭辞を変更すること
- 固有のキーコードを設定すること
- プラグインで済ませてよいか検討すること
- ディレクトリへのアクセスを制限すること
- 管理画面へのアクセス制限を強化すること
- エラー表示を抑制すること
- ユーザの権限を制限すること
- パスワードの強度を上げること
- システムとプラグインのアップデート
- その他
ここでは、共有のレンタルサーバにインストールするユーザを想定しています。WordPress のセキュリティ対策については、たくさんのブログエントリーが存在するので、既にみなさんもよくご存知の対策がある筈です。しかし、本当にセキュリティ対策になっているのか、もしかすると逆効果ではないかというコメントが寄せられていることもあります。そこで今回は、補足として四つのポイントを取り上げてみます。(なお、注釈するまでもないと思いますが、これで全てではありませんし、これらが適切なポイントである保証もありません。)
僕は WordPress 関連のサイトやセキュリティ関連のサイト、あるいはブログの RSS を Google Reader で毎日ながめています。ざっと見ているだけですが、ときどき WordPress のセキュリティに関する「10のなになに」、「20のしかじか」という、いまとなってはありふれたタイトルの記事についても、ひとまず目を通しています(中身まで凡庸とは限らない記事もあるからです)。例えば2009年7月13日に Syed Balkhi さんが Six Revisions に掲載した「WordPress のセキュリティに欠かせない12のヒントとワザ(”12 Essential Security Tips and Hacks for WordPress”)」という記事は、次のような項目でセキュリティ対策を紹介していました。
- MySQL のデータを定期的にバックアップすること
- wp-admin フォルダを保護すること
- 使っている WordPress のバージョンを公開しないこと
- WordPress 本体を最新版にアップデートし続けること
- ディフォールトの “admin” という管理者ユーザを使わないこと(できれば削除すること)
- WordPress 関連の Cookie に保存されるデータを暗号化すること
- 強いパスワードを設定すること
- テーブル名の接頭辞を変更すること
- ファイルのパーミションを適切に設定すること
- 検索エンジンに不必要なファイルやディレクトリを走査させないこと
- 管理画面には SSL 接続を使うこと
- wp-config.php へのアクセスを遮断すること
おおよそ、強調した項目は僕の記事でも紹介しました。但し、管理画面を SSL で接続できるようにするという対策は、レンタルサーバのユーザには難しいかもしれず、また多くのレンタルサーバでは共有の SSL 接続すら提供されていないという理由で、僕の記事では紹介だけしておいて、推奨すべき対策からは除外しています。なお、ファイルのアップロードに SSL 接続の FTP ウェブアプリケーションが使えるレンタルサーバを推奨できると書きましたが、これは上記の 11. とは意味が違います。
ポイントその一:難読化
さて、バルキさんの記事に寄せられたコメントの中に、次のようなものがありました。
こうした対策の多くは、セキュリティ対策というよりも難読化(obscurity)だ。
- Lane4
確かにそうですが、お決まりのディレクトリ名ではなく推測困難なディレクトリ名を使うことも、リスクを下げる役には立ちます。従って、「セキュリティ対策というよりも難読化だ」という指摘は、ものごとの呼び方を(たとえ更に正確になっていようと)単に言い直しただけにすぎないでしょう。批評にはなっていないと思います。確かに難読化という処理はセキュリティ対策だけのために存在するわけではありませんが、上記の提案に掲げられている難読化は、そうしたセキュリティ対策以外の目的で使われているわけでもありませんから、カテゴリーミステイクを犯してはおらず、Lane4 さんが難読化にはセキュリティ対策とは別の目的もあるという前提に立って「セキュリティ対策以外の目的で使われている難読化だ」という批評をしていたとしても、それは当たらないでしょう。
もしかすると、難読化はそもそもセキュリティ対策とは全く別の排他的なカテゴリーに入れることが望ましく、それゆえ難読化はセキュリティ対策とは何の関係もないと論ずる正当な理由があるのかもしれません。しかし僕が知る限りそのような人々はおらず、いくらブログのコメントとは言え特殊な前提(いちがいに「誤った前提」とは言えない)を元に一般的な結論を出そうとすれば、その前提がなぜ正しいかを説明しない限り、異なる前提どうしで話をしても水掛け論に終わるでしょう。得てしてそのような議論は「言葉の話なんてどうでもいい」という間違った諦め方に落ち着いてしまうこともあります。
ポイント・その二:wp-admin ディレクトリの保護
それから、次のような論評もありました。
コツのまとめ方としてはよいが、半分以上はセキュリティ対策として誤っているか、もしくは誤解を招くと思う。
#2 は効果的なセキュリティ対策にならない。なぜなら、多くの攻撃は wp-admin の外で起きるからだ。
#3 は全くの無駄だ。それどころか危険ですらある。テーマの wp_head() はサイトの運用にあたって重要な役割を担うことがあるからだ。
#5 はよいアドバイスだが、効果的なセキュリティ対策にはならない。チカラ技の攻撃(ブルートフォース攻撃)は気にするほどよくある攻撃パターンではない。
#7 は WordPress [のユーザ設定画面] にもともと備わっている。これはよく出来ているので、これを使うとよい。
#8 は利口な攻撃者からは WordPress を守ってはくれない。
#10 はアップロードした画像を Google に走査させないので、すぐに逆効果だとわかるはずだ。
#12 は有効だが、wp-config は PHP が動作するサーバでは何も出力しないので、そんな設定をしても意味がないだろう。
- Otto さん
では、上記の批評が指摘するように(僕が紹介した対策の中にも、批評に該当するものがあります)、幾つかの対策は無意味だったり逆効果だったりするのでしょうか。
まず、#2(/wp-admin を保護すること) については、wp-admin 以外のディレクトリやファイルを適切に保護するという条件を付けようとと付けまいと、wp-admin を保護するという処置にはリスクを下げる単独の効果があります。「他のファイルも攻撃されるから」というだけでは、保護すべき対象の優先順位を変えるには根拠が弱すぎますし、その理由だけで wp-admin の保護を軽視できるなら、情報セキュリティの実務は「程度問題へのすり替え」という詭弁に立ち向かう術をもたなくなるでしょう。つまりたちどころに、「あまり誰も攻撃しない」であろう中小零細企業のサーバを預かっている情報セキュリティの実務担当者は必要なくなるに違いありません。それどころか世の中の殆どのブログは、WordPress だろうと Movable Type だろうと、頻繁に攻撃される機会など訪れないちっぽけなサイトに過ぎません。
しかしだからといって、セキュリティ対策をしなくてよいという理由にはならないでしょう。しかも、僕が一連の記事で想定しているのは共有のレンタルサーバを使うユーザさんなので、もしアプリケーションに対する攻撃のせいで任意のコマンドをサーバで実行できてしまえば、自分だけの問題では済まなくなります。データベースやサーバマシンに権限を上昇してアクセスできるような脆弱性を放置すると、他のユーザにも影響が出ます。場合によっては、ssh コマンドによる横移動に同じパスワードが使えてしまったら(そんなホスティング会社はないと信じたいところですが)、同じデータセンターの中で他のラックにまで影響が広がる可能性もありますし、どこまで被害が広がるか分かりません。
確かに、「殆ど誰も攻撃しないのだから、セキュリティ対策など必要ない」と断言してしまう IT 企業の経営者やプログラマは後を絶たないわけですが、実際には、そういうバカどもに気づかれないようにサーバを好きなだけ利用するのが賢いクラッカーなので(つまり、意図せずに表立った被害を出して、サーバ管理者に気づかれてしまうのはヘタレの攻撃者なのです)、「中小企業のサーバなんて誰も攻撃しないんだから」と公言しているセキュリティ意識の低い人々が運用しているサーバは、既に SMTP サービスや cron などが乗っ取られているかもしれません。ということで、Otto さんの上記の論評には教えられる点もありますが、概して「~は一般的でない」とか「~はよくある」などという言い方をセキュリティの話題について臆面も無く使っている点に、いささか不安を感じます。
ポイント・その三:WordPressのバージョン表示を抑制する
次に #3 (wp_head() のアクションをハードコーディングして、WordPress のバージョンが出ないようにすること)を検討してみると、これは Otto さんのコメントの方が正しいと思います。確かに、WordPress に限らず、Apache や MySQL, PHP, Python といったミドルウェアのリヴィジョンが、XHTML ソース、スクリプト言語のエラー、HTTP レスポンスにしたがって出力されるページへ表示されていてもよいかどうかは、サーバの運用に携わっている人たちにとっても、セキュリティに関する実務上のテーマになりえます。
WordPress の場合、<head>…</head> 要素に WordPress の版数を表示しておいてもブログの運用・管理者にメリットはないでしょう。しかし、だからといって wp_head() のアクションからハードコーディングで取り去る必要まであるとは思いません。ちなみに、なんでこんな議論をしているのか分からない方のために補足すると、メタタグとしてバージョン表記に相当する部分が以下のようにテーマファイルに書かれているのはご存知でしょう。
<meta name=”generator” content=”WordPress <?php bloginfo(‘version’); ?>” />
<!– leave this for stats please –>
しかし、これをソースコードから削除しても、wp_head() が呼び出されていれば、この関数に紐付いた generator アクションでもバージョン表記のメタタグが出力されるようになっているのです。実際に、上記のメタタグと wp_head() をどちらも使っているウェブサイトでは、ページのソースを確認すれば、<meta name=”generator” content=”WordPress x.x.x” /> 要素が二回出力されているはずです。
コアのブログシステムにおいて、セキュリティ上の理由から取り除くべきものがあるなら、それは個々のユーザに対してブログの記事で訴えるよりも、WordPress の開発コミュニティに対してフォーラムや ML へ参加して訴える方が効果的であって、プロセスとしても正しいと思います。なぜなら、第一に、個々のユーザがソースコードを書き直していると、アップデートのたびに修正したファイルが上書きされないような処置が独立に必要であって、ソース管理のしくみをエンドユーザに要求することとなるからです。
また第二のもっと本質的な理由として、セキュリティ対策は或るブログ記事を見ている人だけが得すればいいような、ブログの訪問者に対するおみやげ品のような扱いではいけないからです。もちろんオリジナルの対策や試案、あるいは未知の脆弱性があれば、それを自サイトだけに公開しておくのは勿体ないですし、後で話題となったときに「俺はもっと前から気づいていた」などとヲタクの猿山合戦で勝ち上がるための証拠に使うような人も見かけますが、そういった行いは端的に愚劣というものでしょう。
そもそも、昨今のサーバ攻撃やウェブアプリケーション攻撃は、小学生でも扱えるようなツールによって自動化されています。ボットネットなど広範囲に及ぶマシン(それこそ個人サーバから大企業の LAN の末端に繋がっているオッチャンの PC に至るまで)が連携して攻撃することもあり、人手を介さずに攻撃が繰り返されることも珍しくなくなりました。攻撃ツールは、「適切な攻撃」を加えるために、ソースコードに記載されているリヴィジョンの値など最初からあてにしていません。WordPress 1.x で運用しているサイトが WordPress 2.8.4 を名乗ろうと、それだけで攻撃をやめるツールなど、いまどき中学生でも書かないでしょう。クレジットカードの番号を盗むといった、注意を要する手の込んだ攻撃を加えるときは、攻撃回数の制限という問題がありますから事情は異なりますが、巷に出回っている特定のウェブアプリに向けて書かれた攻撃スクリプト(phpBB用 とか WordPress 用とか phpMyAdmin 用とか、いろいろあります)や「ウェブアプリケーションの脆弱性を判定するソフトウェア」の類は、もっと単刀直入に、相手の WordPress のリヴィジョンが 2.8.4 だろうと 9.5.7 だろうと読み取れなかろうと、知られている限りの脆弱性を全て攻撃してきます。あるいは、相手のサーバで WordPress が動いているかどうかなど気にしない場合だってあります(単純にデータベースのデータを引っかき回すといった、いたずらが目的であれば、SQL クエリを任意のテーブルに投げられる脆弱性があればよく、記事を書き直すとか題名を書き直すといった「人間的な」理由で攻撃を試みる必要はありません)。逆に言うと、WordPress のリヴィジョンをいちいち確認して攻撃するのは、特定のリヴィジョンがもつ脆弱性を利用して、特定のことを相手のサイトにやりたいという「人間的な」理由で攻撃している、まさしく人間の攻撃者だけだと言ってよいかもしれません。
[追記:2010-01-21]
Please Note: This does NOT prevent WordPress exploits being attempted against your site, as modern worms ignore the version in their exploit attempts (Note: There are many ways of determining the WordPress version a site uses, the “generator” is a rarely used method.)
WordPress Codex, “Hardening_WordPress“
リビジョンの表記をやめても大した効果はないと言えます。寧ろアップデートするたびにそんな手間をコアのコードにかけるなら、そのアップデートしたという事実こそが基本的なセキュリティ対策になっているので、蛇足も甚だしいと言った方がよいでしょう。
ポイント・その四:よくある攻撃とあまりない攻撃
#5(ブログシステムを “admin” というディフォールトのユーザ名で運用しないこと)については、当記事がレンタルサーバのユーザを対象にしているという前提で次のように考えてみましょう。まず SSL 接続を使わずに管理システムへログインしている方も多く、中間者攻撃(MITM)を受けると、いかなるユーザ名を使っていようと無意味です。”admin” だろうと “P0jm8bZTKEVA4KWR” だろうと、パスワードを何桁に設定していようと、暗号化していない通信には何のセキュリティ上の保護もありません。
では SSL 通信しているサイトに不正アクセスを試みる者や、MITM のできる環境にない状態で不正アクセスを試みる者は、どのような攻撃をするでしょうか。もちろん、アプリケーションの脆弱性を突けるなら、ブルートフォースで攻撃するよりも格段に効率がいいのは確かです。例えば、WordPress のコードには存在しないクズコードの一例ですが、
mysql_query( “SELECT `id`,`pass` from users WHERE id=’” . $_GET[ 'id' ] . “‘” )
こんな馬鹿な書き方をする人間がいないとも限りません。オープンソースであるということは、攻撃者に弱点を晒しているのと同じなので、基本的なペリメータモデルを前提に話をすると、脅威レベルが一定であれば、残る脆弱性レベルの違いは開発者と攻撃者の優劣に加えて、アプリケーションが実装・運営されている個々のサイトについては、サイト運営者自身の運用ポリシーやサーバ管理能力にも左右されます。
