wp-login.phpにBasic認証をかけつつ投稿の「パスワード保護」機能を利用する

セキュリティ対策でwp-login.phpにBasic認証を設定したのですが、「パスワード保護」された投稿を見るにもBasic認証が必要になってしまうので、.htaccessの設定で回避しました。

パスワード保護された投稿

ちなみにWordPress Codexでは /wp-admin/ にBasic認証の付与が紹介されています。

サーバーサイドで /wp-admin/ にパスワードを追加する(Basic 認証など)と、ブログ管理領域、ログイン画面、ファイルに二層の保護を追加できます。

WordPress の安全性を高める – WordPress Codex 日本語版

結論からいうと、wp-login.phpに対するBasic認証を下記の設定にしてやればいいです。(Apache 2.4以上)

# 自サイトのautumnsky.jpからの「パスワード保護」の認証は通す
# それ以外のアクセスはBasic認証を必要とする
# Apach2.4 以上での設定例

SetEnvIf Referer "https://autumnsky.jp/" internal_site

<Files wp-login.php>
AuthUserFile /home/<your_home>/www/.htpasswd
AuthName "Login Page"
AuthType BASIC
<RequireAny>
  Require valid-user
  <RequireAll>
    Require expr %{QUERY_STRING} = 'action=postpass'
    Require env internal_site
    Require method POST
  </RequireAll>
</RequireAny>
</Files>

以下、<RequireAny> 内の説明です。

<RequireAny>Require ディレクティブのどれか一つを満たすアクセスを許可します。

なので、valid-user の他に、パスワード入力フォームからwp-login.phpを呼び出した時の条件を<RequireAny>ディレクティブに追加してやればよさそうです。

保護された投稿のパスワード入力フォームのHTMLは下記となっています。

<form action="https://autumnsky.jp/wp-login.php?action=postpass"
   class="post-password-form" method="post">

そこで、下記条件を全て満たす場合は「パスワード保護された投稿の表示のためのアクセスである」としてBasic認証なしでwp-login.phpを呼び出せるように設定します。

  1. クエリ文字列action=postpass を含む。
  2. 自サイトからのアクセスである。
  3. httpリクエストメソッドがPOSTである。

自サイトからのアクセスかどうかはリファラで判定しますが、Require ディレクティブでは使えないので、一旦、環境変数にします。
SetEnvIf ディレクティブにより、リファラが指定したURLと一致すれば環境変数 internal_site が設定されます。中身はデフォルトの値である 1
Require では、この internal_site の有無を判定する形にします。

参考:mod_setenvif – Apache HTTP サーバ バージョン 2.4

<RequireAll> で囲うと、中の条件を全て満たす時にアクセスを許可しますので、1~3の条件を括ってやります。

  <RequireAll>
    Require expr %{QUERY_STRING} = 'action=postpass'
    Require env internal_site
    Require method POST
  </RequireAll>

これで、

  • Basic認証で確認されたユーザー
    • または
  • 下記条件を全て満たす場合
    • クエリ文字列が action=postpass
    • 環境変数 internal_site が存在する
    • httpリクエストはPOSTメソッドである

となります。

これで、wp-login.phpにBasic認証をかけつつ、投稿の「パスワード保護」機能が使えます。