最近ではドメイン登録後サーバー側で自動的にSSL証明書が発行されるというサービスが定着してきましたね。
非SSL(http)での通信を、SSL(https)での通信に強制する(すべてのhttpアクセスをhttpsへ転送する)ことは、apacheのWebサーバーであれば、以下のコードを.htaccessファイルへ追加することで実装できます。
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
ちなみにきちんとリダイレクトされているかは、「Check Your Redirects and Statuscode」で、わざと「http:~」の投稿または固定ページ(トップページ以外)を指定して、以下のように返ってくれば大丈夫。

もしも「301 Moved Permanently」という記述がなく、「200 OK」だけが表示されたら、非SSLでもアクセスできてしまう可能性があるので処置が必要です。
またこのツールを使わなくても、トップページ以外の投稿や固定ページを表示させて、わざとURLを「http:~」にしてもアドレスバーに鍵マークが付かずに表示されるときは、この転送設定がなされていないわけです。
おっとっと...またタイトルと違うことを始めてしまいました。
でも、サーバー側が自動で無料SSL証明書をしれっと適用し、半ば自然にSSL通信のWordPressサイトが自動でインストールできてしまうので、そうしたことを知らない方も多いかもと思ってまずは補足した次第です。
さて、一応これでSSL通信させることは可能になるのですが、上記のコードでは非SSL通信のプロトコルへのアクセスをSSL通信に強制するだけで、通信中の送信データなどの保護は、HSTS(セキュリティヘッダー)というのを使って細かく設定していく必要があります。
セキュリティヘッダーに関する記述は、ページが表示される(厳密にはページの要素が吐き出される前)に出力される必要があるため、本来は.htaccessに直接記述するのが望ましいようです。
追記
本ページの公開時には、前述のhttpsへの301リダイレクト用コードを直接.htaccessファイルへ記述する方法しかわかりませんでしたが、に方法が分かりましたので、文末で方法を紹介しています。
これを併用すれば、今回のメインテーマであるHSTSの設定も、SSLリダイレクトも両方テーマ側から制御できそうです。
まあ、SSL通信への転送設定と同時に行えば、WordPressの管理画面外から編集するしかない.htaccessファイルの編集も一度で済むので問題ないでしょう。
それに、WordPressには、SSL通信できる環境のサイトをいくつか設定するだけで完全なSSL通信(転送とHSTSの設定)できるようになっているものもあるので、それらを探してインストールすれば済む話かも知れません。
ただ、それらのプラグインでは、環境により、また、WordPressのバージョンなどにより、突然不具合が出たなんていうのもよく耳にしていて、できれば、手動で設定しておきたいところではあります。
そんな中、HSTSの設定項目もどんどん増えていく傾向にあるので、そのたびに何度も.htaccessファイルを編集するよりは、WordPressの管理画面化からできた方が楽なのではないか?ということでようやく本編へと突入します。
結論、HSTSの設定はWordPressの管理画面下で設定できる
検索をしていてもあまり該当するページにはたどり着けない印象でしたが、ざっと調べた限りでは、以下2つのページで紹介されていました。
- 「Boost WordPress Security by Adding Essential Headers through functions.php」
- Adding Security Headers to WordPress Without 3rd-Party Plugins
私が調べた限りでは、日本語のサイトでは素直にプラグインを使う、または、.htaccessファイルへの追加方法が書かれたものしか見つからず、ちょっと残念でした(でも、需要があるかどうかは別として、このページが最初になるのかも...)。
いずれも、有効化しているテーマのfunctions.phpへ追記することで実装できるというもので、前者で紹介されているコード例が以下で、
function hoolite_add_security_headers() {
header("X-Frame-Options: SAMEORIGIN");
header("X-Content-Type-Options: nosniff");
header("X-XSS-Protection: 1;mode=block");
header("Referrer-Policy: no-referrer-when-downgrade");
header("Content-Security-Policy: upgrade-insecure-requests;");
header('Strict-Transport-Security: "max-age=31536000" env=HTTPS');
}
add_action("send_headers", "hoolite_add_security_headers");
「send_headers」というアクションフックを使って、直接的にHSTSを出力するコードになっています。
ただ1点最終行のコードに誤りがあって、
header('Strict-Transport-Security: "max-age=31536000" env=HTTPS');
を
header('Strict-Transport-Security: max-age=31536000; env=HTTPS');
に変更しないと、結果にwarningが出ます(結果の確認方法は後述します)。
また、後者で紹介されているコード例が以下で、
function pagely_security_headers( $headers ) {
$headers['X-XSS-Protection'] = '1; mode=block';
$headers['X-Content-Type-Options'] = 'nosniff';
$headers['X-Content-Security-Policy'] = 'default-src \'self\'; script-src \'self\';';
return $headers;
}
add_filter( 'wp_headers', 'pagely_security_headers' );
こちらは「wp_headers」というアクションフックを使って書かれています。
こちらについては、アクションフックのユーザー投稿メモにあるように、サードパーティーキャッシュ(恐らくキャッシュ系プラグインも含む)では、きちんと動作しない可能性があるので、そうした環境では前者の方法で追加したほうがよいかと思います。
ただ、いずれのコードも必要な項目が足りないので、私は後者のコードを流用して以下のコードをテーマのfunctions.phpへ追加しました。
function pagely_security_headers( $headers ) {
$headers['X-Frame-Options'] = 'SAMEORIGIN';
$headers['X-Content-Type-Options'] = 'nosniff';
$headers['X-XSS-Protection'] = '1;mode=block';
$headers['Referrer-Policy'] = 'no-referrer-when-downgrade';
$headers['Content-Security-Policy'] = 'upgrade-insecure-requests';
$headers['Strict-Transport-Security'] = 'max-age=31536000; env=HTTPS';
$headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains';
$headers['Strict-Transport-Security'] = 'max-age=31536000; preload';
$headers['Permissions-Policy'] = 'geolocation=(), midi=(),sync-xhr=(),accelerometer=(), gyroscope=(), magnetometer=(), payment=(), camera=(), microphone=(),usb=(),fullscreen=(self)';
return $headers;
}
add_filter( 'wp_headers', 'pagely_security_headers' );
このコードは実際に当サイトで現在使用しています
HSTSの設定確認
セキュリティヘッダーで出力されている内容や、正常に機能しているかは以下のサイトでで確認できます。
例えば、上の検証ツールで検証した場合、全く設定していない場合には、以下のような結果画面が出ます。

要は、Headersという項目にあるものが、必要とされるセキュリティヘッダーの項目で、それらが何も設定されていませんよ!という表示です。
これをスタートとして、前述した前者のコードを元に誤りに気付かずその他の項目も追加した際の検証結果が以下の画面です。

一見きちんと設定できている(オールグリーンなので)ように見えるのですが、最終行にWarningという項目があり、「内容については下の該当項目を確認してね(要約)」と書かれています。
ページ内の該当箇所を見ると下図のように表示されています。

要約すると「”max-age”という無効な文字列がありますよ」というものです。
ん?きちんと書かれているのに..と思ったのですが、先に紹介したように、各要素?の区切りは「”」で囲むのではなく、「;」で区切って囲み文字はなしというのがルールのようで(この辺り全く無知です..)、前述したように修正したら、以下のように「A+」というクリーンな状態になりました。

項目の内容はもっと勉強して正しいかどうかを見極める必要がありますが、上記いずれのツールでも問題なさそうなのでこのまま様子を見ることにしました。
今回よく結果を見たので構文の誤りに気づけましたが、やはりコピペというのは怖いなあという印象でした。きちんと勉強せねば!!と再認識しました(これがコード提供者のトラップでないことを願うばかりです)。
以上が、テーマのfunctions.phpがHSTSを出力・制御できないかという疑問に対する結果です。
HSTSについては上記方法で間違いなく適用できるようです。ただ、それもこれも冒頭で書いたように、それ用のプラグインを使ったり、.htaccessに直接追記すれば済む話なので、実際のところは役に立たない情報なのかも知れません..。
本来この件を調べたいのではなくて、リンク埋め込みのあるページでのみ?出現する「Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute」という警告を解除するため、「SameSite Cookie」の問題を解決したかったのですが、結局現在では、サイトサイドの問題ではなく、サーバーサイドの問題なのかもという結論に達し、結構な時間をかけた割には、今抱える問題に対しての解決には至らず残念でした(泣)。
WordPressでリンク埋め込み(wp-embed)を使ったページで同様の現象が発生する方、意見交換できたら幸いです。
セキュリティヘッダーの設定誤りで起きたトラブル例
このページでは、最終的に以下のコードで管理画面から追加する方法を紹介してきました。
function pagely_security_headers( $headers ) {
$headers['X-Frame-Options'] = 'SAMEORIGIN';
$headers['X-Content-Type-Options'] = 'nosniff';
$headers['X-XSS-Protection'] = '1;mode=block';
$headers['Referrer-Policy'] = 'no-referrer-when-downgrade';
$headers['Content-Security-Policy'] = 'upgrade-insecure-requests';
$headers['Strict-Transport-Security'] = 'max-age=31536000; env=HTTPS';
$headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains';
$headers['Strict-Transport-Security'] = 'max-age=31536000; preload';
$headers['Permissions-Policy'] = 'geolocation=(), midi=(),sync-xhr=(),accelerometer=(), gyroscope=(), magnetometer=(), payment=(), camera=(), microphone=(),usb=(),fullscreen=(self)';
return $headers;
}
add_filter( 'wp_headers', 'pagely_security_headers' );
セキュリティヘッダーを出力する方法としては、.htaccessへ直接追加するのが結構いろいろなサイトで紹介されていて、それを参考に追加している方多いと思いますが、私が実際に遭遇した経験として、追加した途端に他のドメインのサイトでWordPress標準のリンクカードが表示されないトラブルが発生しました。
これが.htaccessへ記述したからなのか、コードの誤りなのかは調べていませんが、WordPressで作成したサイトの投稿は、特にカード表示用のデータ出力を止めたり拒否したりしていなければ、どのサイト同士でも問題なくカード化されるはずですので、カード化されずにタイトルリンクだけになったり、エディター側でアクセスが拒否されたと表示される場合には、セキュリティヘッダーの出力を一旦止めてみると解決することがありますから試してみてください。
SSL通信への301リダイレクトをテーマ側から設定する方法
冒頭あたりで書きましたが、本ページの公開時点では分からなかった、非SSLページ(http:~)をSSLページ(https:~)へのリダイレクトについて、.htaccessファイルの編集なしで、WordPressのテーマやプラグイン側から設定する方法が分かりましたので、おまけとして紹介しておきます。
以下をテーマのfucntions.phpへ追加するだけで機能します。
function ssl_redirect_add_to_htaccess( $rules ) {
$content = <<<EOD
#<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
EOD;
return $content . $rules;
}
add_filter('mod_rewrite_rules', 'ssl_redirect_add_to_htaccess');
このコードを追加して保存した後、「設定」→「パーマリンク設定」で何もしないで「変更を保存」をクリックして、リライトルールをフラッシュしてください
この処置で使用するフック:mod_rewrite_rules
参考:Help Code Review – I need to write on .htaccess file from theme’s function.php
通常、直接.htaccessファイルへ追加する場合には、ファイル内の「#BEGIN WordPress」という宣言の前に追加する必要がありますが、このコードはWordPressのリライトを行う記述に追加するフックなので、「#BEGIN WordPress」~「#END WordPress」の間の先頭にコードが差し込まれる形になります。行っていることは同じなので、動作に問題はないでしょう。
また、前ではなく、後ろに差し込みたい場合には、returnの記述の前後を以下のように入れ替えればOKです。
return $rules . $content;
ここでは301のリライトルールを追加しましたが、.htaccessファイルへ行うモジュールは、テーマ側から制御できそうです(未検証です)。
コメントを残す