WordPressのログインページのURLを変更する

前回の記事で書いてる通り、機械的にログインを試みる攻撃を受けていたので対策を施しました。特定IPアドレスからの攻撃だったのでそのIPをブロックしようかと思ったのですが、他のIPに変えられるたびにやるのも面倒なので、Wordpressのセキュリティ策としてよく挙げられているログインURLの変更を実施しました。

初期設定のログインURLはWordpressのドキュメントを見れば分かっちゃいますからね。

方法はいろいろありますが、手軽な方法としてプラグインを使うことにしました。

選んだのは、 All In One WP Security です。もっとシンプルな、URLの変更に特化したやつとかもあるのですが今後別の対策を考える時があったら使いまわせるのがいいと思ったのでこれを選びました。(結果的にURL変更だけで攻撃が収まったのですが、対策前の時点ではそれだけで完了するかどうわかりませんでしたし。)

WordPressの管理画面からプラグインの画面を開き、新規追加から検索してインストールします。そして有効化します。

有効化したら左ペインのメニューに「WPセキュリテイ」というのができるのでここから設定します。

「総当たり攻撃」というカテゴリ(英語だとBrute force)の中の、Rename login page タブがログインURLの変更です。それを開きます。

Enable rename login page feature: のチェックボックスにチェックを入れ、Login page URL: のテキストボックスの中にこれから使うURLを設定しSaveするとそちらが新しいログインページになります。

これで、デフォルトのログインページにアクセスしてみてフォームが出てこないことを確認したら完成です。

WordPressは未ログイン状態でログイン後の管理画面のURLにアクセスするとログインURLにリダイレクトされたりするのですが、このツールでURLを変更するとその動作もなくなり、リダイレクトによってURLがバレるということも防いでくれています。気がききますね。

そして、肝心の攻撃に対する効果ですが、apacheのログを見ると該当の攻撃者に404エラーが出た段階でピタリとアクセスが止まってるのを確認できました。Lightsailのリソースも回復しており良い感じです。

今回の事象への対応はこれで完了ですが、時々不自然にアクセスが集中している時間があったりなどの不穏な動きはまぁまぁあるので必要に応じて今回導入したAll-In-One Securityの各機能を活用して対策して行こうと思います。

Lightsailで立てたWordPressサーバーのapacheログについて

新年のご挨拶でちょっと書きましたが、このブログが昨年末に攻撃を受けていたようで、過剰なアクセスによりCPUリソースが枯渇する事態となっていました。

下にコンソールで確認したCPUリソースの画像を貼りますが、パーストキャパシティがなくなってますね。この時間帯、ブログの表示が非常に遅くなってしまっていました。最終的にどうやって対策し事象を解消したたかは次の記事に書くとして、この時の状況調査のためにログファイルを確認したのでその時調べたあれこれを記事にまとめておきます。

このCPUが異常に利用されていた時なのですが、ブラウザではなくコマンドかプログラムか何かしら機械的なアクセスがされていたようで、Google Analyticsでは特にアクセスの増加等が見られませんでした。GAはブラウザでアクセスしてJavaScriptが動かないとデータが取れませんからね。

ということで、サーバー側のログを調べる必要性が発生したわけです。

通常の構成であれば、apacheのログはデフォルトでは、/var/log/ の配下にあるそうです。
/var/log/apatche か、 /var/log/httpd/ のどちらかの下に。

ただし、LightsailのWordpressはbitnamiというパッケージが使われており、apache自体が通常と違う場所にあって、ログファイルも普通と違う場所にあります。ちなみにapacheがインストールされている場所は次のようにして確認できます。

$ which httpd
/opt/bitnami/apache2/bin/httpd

/opt/bitnami の配下にあることがわかりますね。

そして、ログファイルもこの近辺にあります。/opt/bitnami/apache2/log ってディレクトリがあるのです。一応中見ておきますか。

$ ls /opt/bitnami/apache2
bin  bnconfig  build  cgi-bin  conf  error  htdocs  icons  include  logs  modules  scripts  var


$ ls /opt/bitnami/apache2/logs/
access_log              access_log-20210801.gz  error_log-20200223.gz  error_log-20210808.gz
access_log-20200223.gz  access_log-20210808.gz  error_log-20200302.gz  error_log-20210816.g
access_log-20200302.gz  access_log-20210816.gz  error_log-20200308.gz  error_log-20210822.gz
access_log-20200308.gz  access_log-20210822.gz  error_log-20200316.gz  error_log-20210829.gz
#########
#  中略  #
#########
access_log-20210704.gz  access_log-20221218.gz  error_log-20210712.gz  error_log-20221226.gz
access_log-20210712.gz  access_log-20221226.gz  error_log-20210718.gz  error_log-20230101.gz
access_log-20210718.gz  access_log-20230101.gz  error_log-20210726.gz  httpd.pid
access_log-20210726.gz  error_log               error_log-20210801.gz  pagespeed_log

名前から明らかですが、access_logがアクセスログで、error_logがエラーログであり、日付がついて拡張子が.gzになっているのがログローテションで圧縮された古いログです。

ちなみにこのログファイルのパスは、次の設定ファイルで設定されています。

$ vim /opt/bitnami/apache2/conf/httpd.conf

# 中略

<IfModule log_config_module>
    #
    # The following directives define some format nicknames for use with
    # a CustomLog directive (see below).
    #
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      # You need to enable mod_logio.c to use %I and %O
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>

    #
    # The location and format of the access logfile (Common Logfile Format).
    # If you do not define any access logfiles within a <VirtualHost>
    # container, they will be logged here.  Contrariwise, if you *do*
    # define per-<VirtualHost> access logfiles, transactions will be
    # logged therein and *not* in this file.
    #
    CustomLog "logs/access_log" common

    #
    # If you prefer a logfile with access, agent, and referer information
    # (Combined Logfile Format) you can use the following directive.
    #
    #CustomLog "logs/access_log" combined
</IfModule>

# 中略
#
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here.  If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog "logs/error_log"

#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
LogLevel warn

CustomLog / ErrorLog がファイルパスの指定で、LogFormatとしてログの出力書式も指定されていますね。
書式の%hとかの意味はこちらのドキュメントにあります。
参考: mod_log_config – Apache HTTP サーバ バージョン 2.4

あとは中身を確認したら良いです。access_log とかのファイルはapacheがアクセスがあるたびにバリバリ書き込んでる物なので、ロックがかからないようにこれを直接開くのは避けて、どこかにコピーして開きましょう。scp等でローカルに持ってきちゃうのが良いと思います。

拡張子が.gzのものは、gzip コマンドに -d オプションをつけて実行すると解答できます。

# *(アスタリスク)を使ってまとめて解凍しちゃうと楽。
$ gzip -d *.gz
# .gzファイルが無くなり、解凍済みファイルだけが残ります。

あとはただのテキストファイルなので、出来上がったファイルを確認したら良いです。

この結果、冒頭に挙げた攻撃を受けてた時間帯は、ログインを試みるアクセスが特定のIPアドレスから7万回も発生していたのがわかりました。

基本的に通常のアクセス分析はGoogle Analyticsを見れば済む話なのでapacheのログに意識をはらってきませんでしたが、今回調査してみてもっと使いやすいフォーマットで出力するように設定しておけば良かったなと思いました。csvではないのでpandasでのパースも面倒でしたし、User Agentなど取れるはずなのに取ってない情報も多かったので。そしてタイムゾーンも日本時間じゃないんですよね。これも地味に扱いにくいです。

WordPress 5.X系のブロックエディタで Prism.js を使う方法

WordPress 5系で新しくなったエディタ(ブロックエディタ、もしくはGutenbergというらしいですね)を使いにくいと感じていたので、つい最近まで4系のまま使い続けていたのですが、サポート期間終了の警告が出るようになってしまったので、諦めて5系にバージョンアップしました。

この新しいエディタには慣れるしか無いので諦めて使っていこうと思います。

実は先日のBar Chart Raceの記事はブロックエディタで書いたのですが、ソースコードのシンタックスハイライトをやってくれているPrism.js を動作させる方法がなかなかわからず苦戦したので、使い方を記録しておこうと思います。

Prismjs のページで公式な対処法を探したのですが、そこでは記載を見つけられなかったのであくまで僕はこうやって解決したという非公式な方法になります。

具体的には、次の手順でprismjsが動作してくれます。

  1. ブロックを追加するときに、「コード」のブロックを選択して追加する。
    もしくはブロック追加後に + ボタンを押して「コード」に変換する。
  2. 右ペインのメニューの「ブロック」の「高度な設定」タブを開き、追加 CSS クラスに「language-python」など、有効化したい言語のクラスを設定する。

例えば、ブロックを「コード」にしただけで、追加CSSを設定しないと次のような表示になります。

print("Hello World!")

追加CSSにlanguage-pythonを入れるとこうなります。

print("Hello World!")

公式ドキュメント等で確認できてないので少々不安ではありますが、ちゃんと動作してるように見えますね。

LightsailのWordPressにads.txtを設置する

Googleアドセンスの管理画面に入ると、

要注意 – 収益に重大な影響が出ないよう、ads.txt ファイルの問題を修正してください。

という警告が出続けているので、対応することにしました。

ads.txtについての説明は以下のページなどをご参照ください。
広告枠の管理 ads.txt に関するガイド
Ads.Txt – Authorized Digital Sellers

さて、早速作業していきます。
まず、配置するads.txtファイルを入手します。

これは、Googleアドセンスの警告の右側に表示されている「今すぐ修正」をクリックすると、
「ダウンロード」できるようになります。

ダウンロードしたファイルをサイトのルートディレクトリ(トップレベル ドメイン直下のディレクトリ)に配置します。

LightsailのWordpressの場合、
/home/bitnami/apps/wordpress/htdocs/ads.txt
に配置すればOKです。
scpか何かでアップロードしても良いでしょうし、たった1行なので内容をコピーして貼り付けても良いでしょう。

htts://{サイトのドメイン}/ads.txt
にアクセスして、ads.txtファイルの内容が表示されたら成功です。

クローラーが検知してくれるのを気長に待ちましょう。
クローリングしてくれたらGoogleアドセンス管理画面の警告も消えるはずです。

wordpressの記事の投稿名の一覧を確認する

先日偶然見つけたのですが、このブログのある記事のURL(パーマリンク)に日本語の文字列が混ざっていました。
全部英数字とハイフンで統一するようにしているので、その記事については修正したのですが、他にも設定し忘れているのがないか不安になって調べたのでその方法のメモです。

正直、記事数はそんなに多くないので、日本語が混ざってないかどうか確認するだけであればURLの一覧さえ取得できれば目視で確認できます。
で、管理画面で探したのですが、「記事のURL一覧エクスポート」、みたいな機能は見つかりませんでした。
そう言うプラグインはあるらしいのですが、一回確認するだけのためにプラグインを入れるのも嫌なので、DBから直接取得することにしました。

このブログのパーマリンクは、
https://analytics-note.xyz/%category%/%postname%/
という構成で設定しているので、postname(投稿名)の一覧を取得すれば良いです。

まず、こちらの記事で書いた方法でDBにログインします。
参考: LightsailのMySQLに接続する

DB名の確認。


mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| bitnami_wordpress  |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

この中で、bitnami_wordpressが目当てのDBなので切り替えます。


mysql> use bitnami_wordpress;
Database changed

wordpressのデータベース構造についてはこちらにドキュメントがあります。
参考: データベース構造 – WordPress Codex 日本語版

記事の情報は、 wp_posts というテーブルに入っています。
この中の、 post_type が、 ‘post’のものが記事です。
そして、 post_status が ‘publish’ のものが公開中の記事になります。
目当ての URLに使われる投稿名は、 post_name 列に含まれています。
あとは日本語のタイトルである、 post_title 列と一緒に表示するSQL を書いて実行すれば、投稿名の一覧が取得できます。


mysql> SELECT
    post_title,
    post_name
FROM
    wp_posts
WHERE
    post_type = 'post'
AND
    post_status = 'publish'
;

これで確認できました。

WordPressのテーマ Twenty Seventeen のフッターを変更する

これまで、せっかく子テーマを設定したりblogの開発環境を立ち上げる方法を調べたりしたので、1箇所くらい修正してみようと思います。
修正したいのは、ブログの一番下のフッター部分です。
デフォルトでは、
「プライバシーポリシー / Proudly powered by WordPress」
となっています。
プライバシーポリシーへのリンクはそのままでいいですが、 Proudly powered by WordPress は特にいらないですね。
代わりに入れたいのはコピーライト表記です。
また、プロフィールページ(これはそのうち作りたい)がまだないので、
その代わりとして、LinkedInあたりへのリンクを作りたいと思っています。

さて、WordPressのテーマを子テーマを用いて修正する場合、
子テーマのディレクトリの配下に、親テーマと同じ配置でファイルを作ると、それが上書きされて動作します。
参考: WordPressの子テーマのページ

つまり、
(略)/themes/twentyseventeen-child/footer.php
と言うファイルを作ると、このファイルが、
(略)/themes/twentyseventeen/footer.php
を上書きして動作します。

現在利用している Twenty Seventeen の場合、 footer.phpの作りが少し特殊です。

get_template_part( 'template-parts/footer/site', 'info' );

とある通り、
(略)/themes/twentyseventeen-child/template-parts/footer/site.php
というファイルを読み込んでそれを表示しています。

開いてみると以下の内容でした。確かにこれがフッターの本体のようですね。


<?php
/**
 * Displays footer site info
 *
 * @package WordPress
 * @subpackage Twenty_Seventeen
 * @since Twenty Seventeen 1.0
 * @version 1.0
 */

?>
<div class="site-info">
        <?php
        if ( function_exists( 'the_privacy_policy_link' ) ) {
                the_privacy_policy_link( '', '<span role="separator" aria-hidden="true"></span>' );
        }
        ?>
        <a href="<?php echo esc_url( __( 'https://wordpress.org/', 'twentyseventeen' ) ); ?>" class="imprint">
                <?php
                        /* translators: %s: WordPress */
                printf( __( 'Proudly powered by %s', 'twentyseventeen' ), 'WordPress' );
                ?>
        </a>
</div><!-- .site-info -->

これを上書きするように子テーマにファイルを作成します。

なのでファイルの置き場所は以下になります。
(略)/themes/twentyseventeen-child/template-parts/footer/site-info.php

中身はこんな感じで作ってみました。
(blogのURLと名前は、bloginfo(‘url’)とbloginfo(‘name’)でそれぞれ取得できるみたいです。)


<?php
/**
 * Displays footer site info
 *
 * @package WordPress
 * @subpackage Twenty_Seventeen
 * @since Twenty Seventeen 1.0
 * @version 1.0
 */

?>
<div class="site-info">
    <?php
        if(function_exists('the_privacy_policy_link')){
            the_privacy_policy_link('', '<span role="separator" aria-hidden="true"></span>');
    }
    ?>
    <a href="https://www.linkedin.com/in/yutaro-honda/">LinkedIn</a>
    <span role="separator" aria-hidden="true"></span>
    <a href="<?php bloginfo('url');?>">
        &copy; 2019 <?php bloginfo('name');?>
    </a>
</div><!-- .site-info -->

これでフッターを編集できました。

WordPressのテーマに子テーマを設定する

ほとんど初期設定で運営しているこのブログのデザインなのですが、将来的にはより読みやすい形へのカスタマイズもしたいと思っています。
その場合、子テーマというのを使ってそれをカスタマイズするのがお作法らしいです。

メインのテーマが、WordPressが用意してくれている、 Twenty Seventeenなのですが、これが時々バージョンアップがあり、
子テーマを作っておかないと、その度に自分のカスタマイズ分がリセットされるからだそうです。
(このテーマ特有の事象ではなく、自作ではないテーマを使う人全体に言えることです。)

ということで、子テーマの設定をしました。
なお、このブログのサーバーには、 Amazon Lightsail を利用しています。

子テーマの作成にあたって参照したドキュメントはこちらです。
子テーマ – WordPress Codex 日本語版

管理画面からGUIで作れると思っていたのですが、サーバーに入って作業が必要みたいですね。
まず、ディレクトリ作成からです。 wp-content/themes ディレクトリ下に、親テーマと並列で子テーマのディレクトリを作ります。
(親テーマの配下ではないので注意が必要です。) Lightsail の場合、 wp-content/themes は次の場所にあります。
このディレクトリを探すのにも少してこずりました。

~/apps/wordpress/htdocs/wp-content/themes/
直下に親テーマになる twentyseventeen のフォルダもあります。

ここに、ディレクトリを掘って、style.css, functions.php の2ファイルを作ります。


$ mkdir twentyseventeen-child
$ cd  twentyseventeen-child
$ touch style.css
$ touch functions.php

そして、作った2ファイルに内容を書きます。
まず、style.css の方は、スタイルシートヘッダで始める必要があるそうです。(今回は子テーマ作るだけなので、スタイルシートヘッダだけです。)
具体的にどう書くかは、ドキュメントの記載例に加えて、親テーマのstyle.cssも見ながら次の様にしました。
Template行は、親テーマのディレクトリ名を指します。この例では親テーマが Twenty Fifteen テーマですので、Template は twentyfifteen です。別のテーマが親テーマの場合、該当のディレクトリ名を指定してください。
とある通り、 Template行 が重要です。僕は最初、何も考えずに親テーマのヘッダーをコピーしただけで済ませようとして、Template行がなくてハマりました。


/*
Theme Name: Twenty Seventeen Child
Author: Yutaro
Author URI: https://analytics-note.xyz/
Template: twentyseventeen
Version: 2.3
Requires at least: 4.7
Requires PHP: 5.2.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: twenty-seventeen-child
*/

次は、 functions.php です。 これはドキュメントに指示された通り次の様に書きます。
<?php の部分重要です。PHP の開始タグではじめろとドキュメントの説明にはありますが、コードの例には入っていません。


<?php
add_action( 'wp_enqueue_scripts', 'theme_enqueue_styles' );
function theme_enqueue_styles() {
    wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );

}

ここまで済ませばあとは管理画面から作業できます。
左ペインの外観を選ぶと、空っぽのテーマができているのでこれを有効化するだけです。
いくつかの設定がリセットされてしまうので、それは再設定が必要になります。
(このブログでいえば無効にしていたヘッダー画像が復活するなど。)

WordPressの記事URL変更のためにリダイレクトの設定をする

ずっとこのブログのカテゴリを整理したかったのですが、先延ばしにしているうちに「プログラミング」の記事が150を超え、
このブログの半分程度をしめるようになってしまいました。

明確に困るということはないのですが、もう少しカテゴリーを整理したいと思っています。
その時に問題になるのがパーマリンク(URL)です。

このブログではパーマリングにURLを含めているのでカテゴリーを見直すとURLが変わってしまいます。
そうなると、せっかく検索などから訪問してくれる人がいらしても目的のページにたどり着きませんし、
各記事間のリンクもリンク切れになってしまいます。

そこで、ありきたりな方法ですがリダイレクト設定を入れていくことにしました。
手軽に設定する方法を調べたところ、
Redirection というプラグインが定番のようなのでこれを使います。
参考 : Redirectionプラグインのページ

いつものように、Wordpress管理画面の左ペインのプラグインから、新規追加で検索してインストールと有効化します。
ツールのところに Redirection が現れたので選択。
みたところ、初期設定が必要なようでした。

オプションとして、次の3項目がありました。
Monitor permalink changes in WordPress posts and pages.
Keep a log of all redirects and 404 errors.
Store IP information for redirects and 404 errors.

どうやらパーマリンクの変更を勝手に検知して設定を入れてくれたり、404エラーを監視してくれたりするようです。
実はリンク変更時の設定は全部手作業でやらないといけないといけないと勘違いしていたので非常にありがたいです。
チェック入れて進みます。(後でも変更できるそうです)

最後に、既存の設定をインポートするかどうか聞かれて終了になりました。
(既存の設定に何も心当たりがなかったのですが、以前タイプミスして一瞬だけ間違って公開し、すぐ修正したULRが取り込まれました。)

これであとは、リダイレクト元とリダイレクト先のURLを設定していけば、使えます。

設定画面からログの保存期間等も設定できるので、慣れるまでは長めに保存するよう変えておきました。
(デフォルト 1週間、 設定変更後 1ヶ月)

WordPressにお問い合わせフォームを作る

このブログに問い合わせフォームをつけることにしたのでその手順のメモです。
複数のプラグインがあるようですが、比較的情報が多かった Contact Form 7 を使うことにしました。

まずはプラグインをインストールします。
– ダッシュボードの左ペインのプラグインをクリック
– Contact Form 7 を検索
– 今すぐインストールボタンからインストール
– インストールしたら有効化ボタンをクリック
– 左ペインに お問い合わせ メニューができたことを確認

新しくできた お問い合わせメニューを選択すると、最初からコンタクトフォーム1というフォームができていました。
設定項目がたくさんあるのですが、ざっと見た限りではそのまま使って問題なさそうなのでデフォルトで使います。

このショートコードをコピーして、投稿、固定ページ、またはテキストウィジェットの内容にペーストしてください:
というコメントの下に貼り付け用のコードがあるのでそれをコピーします。

これをブログ内のどこかに貼れば完成するのですが、サイドバーに置くことにしました。
ウィジェットの一覧から「テキスト」を選択し、ブログサイドバーに追加します。
そして、テキストの本文部分に先ほどの貼り付け用のコードを挿入して完成です。

あとは各ページに表示されたので送信テストを行いました。

WordPressでコメントのブラックリストを登録する方法

まだ公開しているコメントは一つもいただけていない本ブログですが、実はスパムのような投稿は日々投稿されています。
キーワードやIPアドレスにもだいぶ法則性が見えてきたのでそろそろ対策することにしました。

(日本語設定している場合)
Wordpressの管理画面の左ペインで、「設定」 => 「ディスカッション」 と選ぶと、
コメントブラックリスト という設定項目があります。

説明にある通り、ここによく貼られているURLやIPアドレスなどを入れておけばそのコメントは自動的にゴミ箱に入るようです。
このブログの趣旨に沿ったコメントであれば確実に登場しないような単語をいくつかピックアアプして設定しておこうと思います。

コメントの内容、名前、URL、メールアドレス、IP アドレスに以下の単語のうちいずれかでも含んでいる場合、そのコメントはゴミ箱に入ります。各単語や IP アドレスは改行で区切ってください。単語内に含まれる語句にも一致します。例: 「press」は「WordPress」に一致します。