WordPressのセキュリティ強化

最近ここを放置気味だが、放っておくと Akismet が弾いてくれた spam コメントが大量に溜まってしまうので、しつこい輩は IP でアク禁にしたりしていた。しかしあまりに多すぎるのでおかしいと思い、久々アクセスログを覗いてみたら、wp-login.php へのアクセスがとんでもないことに。

なんだこりゃあ

11,496? ちょっと異常すぎるだろ!

何やら最近 WordPress の改ざんを狙ったブルートフォースアタックが流行っているそうなのだ。このブログはユーザー名が admin のデフォルトのまま。パスワードが一般的なワードでないとはいえ、これはマズイ。対策のためにプラグインを探したら以下のが良さそうなので入れてみた。

 Force Email Login   作者:Takayuki Miyauchi

データベースやユーザー名に変更を加えずに、ログインユーザー名を WordPress のユーザーメールアドレスに変更するプラグイン。ログインに失敗すると10秒おかないとログイン画面が表示されないので、ロボットに有効だ。

さあて、これでまずは一安心と思っていたのだが、今日になったらデータベースサーバーが不安定なのかブログが表示されにくい。もしやと思いリアルタイムログを覗いたら、どうやらクラッカーに目をつけられたのか、IPアドレスを変えて何度も wp-login.php に数秒おきにアクセスされている。ひい。

こりゃアカンと思って色々考えた挙句、.htaccess で wp-login.php 自体のアクセスを規制することにした。Wordpress をインストールしてあるディレクトリ直下にある .htaccess ファイルを一旦ダウンロードし、以下の文を挿入して上書き。

<Files "wp-login.php">
  order deny,allow
  allow from .jp  # .jpドメインに一致したらアクセス可
  deny from all    # 他は全部アクセス不可
</Files>

 
私の使っている ISP やスマホは全部 .jp ドメインなので、.jp ドメイン以外は wp-login.php へのアクセスを全部禁止するという乱暴なやり方。クラックしようとしているのはウクライナやらロシア、中国ばかりなので、とりあえずこれで問題ないだろう。もし .jp ドメイン以外の ISP も使っている場合は、allow from のあとに ISP のルートドメインなり、固定IP を入れればいい。

本来はこんな大雑把でなく、あくまでも自分が使っているISPに絞って規制するのが一番安全だが、出先のフリースポットで更新したいとか、自宅サーバーでやってるという人は以下のように色々設定しないとならないかも。

<Files "wp-login.php">
  order deny,allow
  allow from .jp
  allow from .bbtec.net     # Yahoo BB
  allow from .wakwak.com    # WAKWAK
  allow from 192.168.        # LAN 上のローカルマシン
  allow from 127.0.0.1        # ローカルテスト用
  deny from all
</Files>

 
.htaccess にドメイン参照させるとパフォーマンスが落ちるのであまりやりたくなかったのだが、固定IPじゃないから仕方ない。でも設定した途端、データサーバーへのアクセスがなくなり効果てきめん。

– [Thu Sep 12 22:59:41 2013] [error] [client 5.234.78.117] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 22:59:41 2013] [error] [client 5.234.78.117] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 22:59:43 2013] [error] [client 5.234.78.117] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 22:59:43 2013] [error] [client 5.234.78.117] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:03:08 2013] [error] [client 95.78.221.63] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:03:08 2013] [error] [client 95.78.221.63] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:11:39 2013] [error] [client 177.108.34.225] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:11:39 2013] [error] [client 177.108.34.225] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:11:44 2013] [error] [client 108.214.134.32] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:11:44 2013] [error] [client 108.214.134.32] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:12:21 2013] [error] [client 95.78.221.63] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:12:21 2013] [error] [client 95.78.221.63] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:13:35 2013] [error] [client 222.166.214.38] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:13:35 2013] [error] [client 222.166.214.38] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:13:40 2013] [error] [client 222.166.214.38] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:13:40 2013] [error] [client 222.166.214.38] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:19:30 2013] [error] [client 31.192.129.159] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:19:30 2013] [error] [client 31.192.129.159] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:19:40 2013] [error] [client 213.87.141.209] client denied by server configuration: /*****/wp-login.php
– [Thu Sep 12 23:19:40 2013] [error] [client 213.87.141.209] client denied by server configuration: /*****/wp-login.php

しかし生ログは見ていると心臓に悪い・・・

スパム退治しながらサイトの引き際を考える

ここで使っているWordPressにはAkismetというコメントスパムをはじくプラグインを入れている。使い始めの頃は誤作動が多かったのだが、最近はかなり精度が良くなってきた。それでもくぐり抜けるspamもあるため、私はコメントにURLが一つでも入っていれば承認待ちにして即時投稿されないようWordPressで設定している。

spam判定されるコメントは大抵英語や意味不明のアルファベットの羅列+URLだったりするのだが、最近になって日本語のものが出始めてきた。文章を見るといかにも自動翻訳っぽい。英文のものもそうだが記事の内容に一切触れず、このサイトは素晴らしい的なことを書くのがこの手のコメントの特徴。どうせ読んでもいないのだろう。とりあえずネタ用にキャプチャしてから即刻削除。

この手のspamは宣伝のためがほとんど。以前よりは減ったがウィルスやマルウェアをバラ撒くためにリンクを貼りまくるボットも少なくない(過去記事:スパムボット)。もちろんそのリンクを踏ませるのが目的なのでけしてクリックしてはならないし、放置してはならない。リファラ情報(どのサイトから来たかというリンク元のURL)等を拾ってさらに自サイトへの攻撃が増える可能性がある。もちろん不意にリンクを踏んでしまう訪問者にも迷惑だ。

もしリンク先を確認したいときはそのURLをコピーして別窓にペーストして開くこと。ただしURLに「.cgi」や「.php」、「.shtml」、「.asp」、「.jsp」、「.do」、「」、「」などが含まれる場合は要注意。ビーコンを仕込んでどこのサイトからのリンクか特定できる変数を送ってしまう場合がある。やたらに長いURLや数字の羅列のあるものはページそのものを開かない方が無難だ。

Googleなどの検索エンジンは他サイトからリンクを数多くされているサイトを優良と認識してランク付けしている。そういったSEO対策のため、躍起になってあちこちのブログや掲示板にコメントを書き捨てる輩も多い。もしリンク先が当たり障りのないものであっても油断は禁物。検索上位に上がったところで何かをしでかしたり、ドメインを悪徳業者に売りさばくということをするかもしれない。いずれにしても節操のない宣伝活動をのさばらせるのはトラフィックの無駄だしネット全体の質を落としかねない(すでに落ちてるが)。見つけた時点で削除するのが管理人のマナーであり、使命だと私は思う。

時々spamコメントを放置したままのブログを見るが、垂れ流しもいいところだ。たとえリンクの貼っていない無意味な文字列でも何に悪用されるかわからない。サイト管理者たる者スパムフィルタリングを導入したり巡回チェックは欠かせないはずだが、実際はそういったことに無頓着な輩が多すぎる。もし自分で管理ができないのならさっさとコメント欄を閉じるか、ブログ/掲示板自体を閉じた方がいい。

イトコが腐女子だったのだが数年前に結婚して今は2児の母。無料サイトにオタク色全開のサイトを開設していたのだが、数年更新もせずに放置してあったので私から注意して削除を手伝った。無料サイト/ブログであっても提供会社がサービスを中止しない限り、利用者が放置しても削除されずに残ること。最近は削除前に「魚拓」と称して画面をキャプチャして保存されることもあること。匿名だからいいやと垂れ流ししたらとんでもないぞとイトコを脅したら青くなっていた。ていうか友人とコスプレしてピースサインしてる写真なんて自分の子供には見せられない黒歴史だし。まあ残念ながら Internet Archive には残っていたけれど・・・

だが管理人がこの世からいなくなって閉じられない場合もあるようだ。ふと思い出して某事件を検索し、その被害者のブログを見に行ってみた。まだそのまま残っていてコメント欄はspamコメントの温床になっていた。こういったブログを停止するには遺族の了解が必要らしく、たとえ無料サービスでも勝手に管理会社側で削除することはしないらしい。垂れ流したつもりでも残ってしまう非情な現実に私も薄ら寒い思いがした。でも私が死んだら数ヶ月以内に料金滞納で自動的に消滅するだろうけれど・・・まあ生きている間は人の迷惑にならない程度にこれからも垂れ流すつもり。

WordPressのカレンダー

このブログの右にあるカレンダーは AJAX Calendar プラグインを利用させてもらっているのだが、最近バージョンアップしたら見た目が若干変わって記事を書いた日が見えづらくなった。色々試行錯誤しながらテーマ編集でスタイルシート (style.css) に以下を記述。バージョンアップ以前よりも統一感のあるデザインにできた。

#wp-calendar {
    text-align:center;
    font:normal 13px/16px Georgia, "Times New Roman", Times, serif;
    }
/* リンク部定義 */
#wp-calendar td a {
    display:block; /* ブロック要素(文字だけでなく要素ごとクリック可に) */
    font-weight:bold; /* 太字 */
    color:#000;
    background:#d7d0b9; /* リンク背景色 */
    }
/* リンクマウスオーバー */
#wp-calendar td a:hover {
    color:#73794f;
    background:#e4ddc6; /* マウスオーバー時背景色 */
    }
/* 前月・来月リンク修飾回避 */
#wp-calendar #prev a {
    text-align:left; /* 左寄せ(block要素がないと無効に) */
    font-weight:normal;
    background-color:transparent; /* 背景色なし(透過) */
    }
#wp-calendar #next a {
    text-align:right; /* 右寄せ */
    font-weight:normal;
    background-color:transparent;
    }

 
うるさすぎず、控えめなマウスオーバーに自画自賛。でも未だCSSってなんか慣れない…

WordPress に GJ! 導入

基本的にこのブログの目的は遠方の友人へ向けての消息情報を報せることと自分のための備忘録。だが、検索エンジンから情報を求めに訪れる方もいらっしゃるようなので、コメントに残さずとも気軽に感想や苦情を言えるようなものがあると便利かなと思いWeb拍手をつけてみたくなった。Minor Problem さんの GJ!(グッジョブ)がよさそうという噂を聞きつけたので導入。若干導入に戸惑うところがあったのでそのカスタマイズのメモ。

現在本サイトに設けているものは 本家Web拍手 の別ページがポップアップで開くものだが、GJ! は JavaScript(最近は Dynamic HTML とか言うのかな)を利用したページ遷移のないタイプのWeb拍手スクリプト。WordPress 専用プラグインではないのでいろいろとソースをいじる必要がある。

まずはモノをダウンロードして gj.js や gj.php の内容を自分用に書き換えてサーバにアップロード。この辺は本家や他のサイトでも解説してあるので割愛。しかしぷりどうぐさんの WordPressにWeb拍手”GJ!”を導入してみた。 にも書いてあるのだが、本家 GJ! サイトの見本スクリプトをコピペすると何故か " (ダブルクォーテーションマーク)などが全角になってしまって動作しない。上記のteraさんのところのスクリプトを利用させていただいたら無事動作。でも出来合いをまんま導入しても若干しっくりこないので以下をカスタマイズ。

まず WordPress 管理画面のテーマ編集で「ヘッダー(header.php)」を編集する際に、サーバー上にアップした gj ディレクトリ内の prototype.js のリンクを貼るようにあるが、これを省略。すべてのテンプレートにあるのかどうかは知らないが、私が利用している環境にはすでに prototype.js がインストールされている。調べてみたら prototype.js とは Sam Stephenson 氏が書かれた JavaScript でさまざまな機能を一から書かずに利用できるAJAXライブラリ。一つあれば動作するだろうと思ったら案の定動いた。なので header.php には、

<script type="text/javascript" src="<?php bloginfo('url'); ?>/gj/gj.js"></script>

 
のみを任意の場所にコピペ。<head>~</head> の間にあればどこでもいいはず(もちろんタグが閉じたところ)。既存の </script> とあるところの下にまるごと行を挿入するのが間違いない。赤文字のように入れれば WordPress が勝手にURLを入れてくれるので各々のURLに書き換える必要ない。ただし prototype.js がインストールされていない環境であれば JavaScript エラーを吐くと思うので、その際は追加しないとダメだろう。なお本家のサイトには何故か改行タグ <br /> が間に挿入されているが、ヘッダーの <head>~</head> に挿入するのであれば必要はないはず。

次に「単一記事の投稿(single.php)」を編集。表示させたい場所に挿入とあるが、ソースを見慣れない人にはイマイチ難しいと思うが、コメント欄の上辺りに置きたかったので <?php comments_template(); ?> を探して以下を挿入。

<br />
<input id="<?php the_permalink(); ?>" type="image" src="" width="81" height="19" alt="Good Job!" title="Good Job!" style="vertical-align:middle; cursor:pointer" onClick="goodjob('<?php the_permalink(); ?>','<?php the_title(); ?>')" />
<input type="text" size="30" id ="<?php the_permalink(); ?>_gj_message" style="background:#e4ddc6; border:1px solid #8d8c87" />
<script>showbutton('<?php the_permalink(); ?>','<?php the_title(); ?>');</script>
<span id="<?php the_permalink(); ?>_gj_mark"></span>
良かったら拍手をどうぞ。短いメッセージも送れます。

 
赤い文字がカスタマイズ、という程のものではないが自分で改造した場所。ボタン上にマウスカーソルが乗っかったときの見栄えを意識したところと、テンプレートに合わせたフォームの見栄えをCSS指定。画像サイズにいちいち指定を入れてしまうのは、少しでも表示の負荷を低減させようという私のこだわりだが、果たして今の高スペックのマシンに意味はあるのかないのか不明。

気軽にクリックさせたいのでどうせなら記事一覧にもボタンを表示させたい。だが一言送信の1行フォームがいちいち表示されるのはスマートではない。なので「メインインデックスのテンプレート(index.php)」と「アーカイブ(archive.php)」には以下のように記述。

<input id="<?php the_permalink(); ?>" type="image" src="" width="81" height="19" alt="GJ!" title="Good Job!" style="vertical-align:middle; cursor:pointer" onClick="goodjob('<?php the_permalink(); ?>','<?php the_title(); ?>')" />
<script>showbutton('<?php the_permalink(); ?>','<?php the_title(); ?>');</script>
<input type="hidden" value="from main index" id ="<?php the_permalink(); ?>_gj_message" />
<span id="<?php the_permalink(); ?>_gj_mark"></span>

 
テキストフォームを hidden にして隠し、「from main index」という値を送信してメインインデックスからボタンが押されたことがわかるように設定。昔からHTML手打ちでサイトを作ってきた人の小細工。ついでにサイトのテンプレの色調に合わせてボタンの色を Photoshop で若干調整。まあこれで出来合いの素材っぽくなくなったんじゃないかと自己満足。

そういえば昔、美大受験の予備校に通っていたとき講師に木炭デッサンを修正されたのだが、少し気に入らなくて直したら「俺が手を入れたところがまたお前の絵になっている」と言われたことを思い出した。何もかんも自分色に染めたい気質は変わらないのね。とはいえゼロからソースを書く技術も気力もないので、こうしたスクリプトや使い方を公開している方には心から敬意を示したいと思います。ありがとうございました。

追記:
GJ! のバグというか環境によって変わると思うけれど、ブログのエントリータイトルによってはボタンが表示されない状況を確認。シングルクォーテーション がタイトルに入っていると、JavaScript の変数送信の際に &#8217; に変換されるにも関わらず、なぜかそこを変数の区切りと誤認識してJSエラーになるという現象。応急的な回避方法としてはエントリータイトルの ‘ をキーワード &rsquo; に置き換えるか、全角 に置き換え。英語で「Dont」とか使う際は「Don&rsquo;t」と記述すればOK。バグ報告させてもらおうと思ったら、開発元のHEX68さんは多忙な様子なので修正は難しそうですね…

2012/06/30 追記
カーソルのCSSの cursor:hand ってのがIE独自仕様だったみたいなので cursor:pointer に修正。あとXHTMLの記述ルールに準じ input タグを閉じるため、半角スペース+/を追加。