さくらレンタルサーバーの共有SSLを使う

さくらレンタルサーバーの共有SSL(https://)を使う際に、.htaccessやPHPスクリプト内で、どの環境変数を評価したらよいかを記述します。またWordPressでの対処法を概説します。

(但し2013年9月21日現在、WordPress3.5の時点の記事です。)

(2017年2月1日:最後のほうのWordpressのパッチに関して、www付きURLについてと、蛇足を追記しました。)

(2016年4月27日追記:さくらレンタルサーバーの、サーバー証明書を設定したSSL(SNI SSL)でも本手法は有効なようです。私が直接試したわけではないのですが…。)

(2013年10月17日追記:さくらインターネットさんから回答が来ましたので、関連箇所に追記しました。)

結論

(私と同様に)困っている方のために結論から書きます。

さくらレンタルサーバーの共有SSLはポート80を使っているので、環境変数SERVER_PORTではSSL接続かどうか評価できません。評価に使える環境変数は以下の通りです。

  • .htaccessでは、SSL接続の時に、%{ENV:HTTPS}が’on’になり、また%{HTTP:X-Sakura-Forwarded-For}にはリクエスト元のIPアドレスがセットされる。
  • PHPでは、SSL接続の時に、$_SERVER[‘HTTP_X_SAKURA_FORWARDED_FOR’]及び$_ENV[‘HTTP_X_SAKURA_FORWARDED_FOR’]にリクエスト元のIPアドレスがセットされる。
  • またPHPでは、SSL接続の時に、.htaccessのRewriteRuleにて書き換えが行われていない場合においてのみ、$_SERVER[‘HTTPS’]及び$_ENV[‘HTTPS’]が’on’になる。

WordPressはRewriteRuleでの書き換えが前提です。従ってさくらレンタルサーバーにインストールしたWordPressでは、共有SSLを利用する場合において、不具合が生じうると考えられます。(Admin SSLのようなプラグインは正常動作しません。)

対処法は後程書きます。

(2013年9月27日追記)さくらインターネットさんのサポートページ「共有SSLの注意点」の「ウェブサーバの挙動>環境変数の取扱い」には以下の様に記されています。

例えば、HTTPとしてアクセスした場合はお手元のコンピュータが、 HTTPSとしてアクセスした場合はサーバそのもの(sakura.ne.jpを含むFQDNのホスト名) がアクセス元となります。このため、SSLのみのアクセス許可(HTTPアクセスの制限)や、mod_rewriteによるURLの書き換えはできません。

「このため」がいまひとつ理解できませんが、「mod_rewriteによるURLの書き換えはできません。」と明記していますので、「もし書き換えを行った場合、その動作保証はできません。」とも解釈できますね。(2013年9月27日追記ここまで。)

(2013年10月17日追記)さくらインターネットさんから回答がきましたので転記します。まず上記のRewiteRuleで書き換えさえると環境変数HTTPSが’on’にならない件について、

> 1. 共有SSLについて、「※mod_rewriteにて書き換えを行わない場合においてのみ
> ※、スクリプト内の環境変数HTTPは’on’にセットされる」という仕様の推測は正
> しいでしょうか?(正誤いずれの場合も、その理由をご説明頂けると幸いです。)

さくらのレンタルサーバで提供している共有SSLは HTTP(80)通信を
Proxy して提供しており、サーバ内部でHTTPS環境変数を ‘on’ に設定
するようサブリクエストを処理しております。

しかしながら .htaccess で mod_rewrite を利用されている場合、
HTTPS(443) によるアクセスと判定できず、HTTPS環境変数が
設定されません。

次に、9月27日追記した件について、

> 2. 御社サポートページの「SSLのみのアクセス許可(HTTPアクセスの制限)や、
> mod_rewriteによるURLの書き換えはできません。」という記載は、(先の質問や
> 本質問に記載しました私のトライアルのように)「可能かもしれませんが、保証
> できません。」というような解釈でよろしいでしょうか?

左様でございます。

動作できないように設定は行っておりません。お客様にて動作できるよう設定
いただく場合は問題はございません。

ということですので、「あくまでも自己責任で」ということですね。(2013年10月17日追記ここまで)

実験

では、さくらレンタルサーバーにおいて、上記結論を検証してみましょう。

準備

適当なディレクトリ(ここではtest)を作成し、以下のようなテスト用のスクリプトを配置します。

環境変数を表示するだけのスクリプトです。(余計なコードもありますが。。。^^;)

test.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>テスト</title>
</head>
<body>
<?php
//	環境変数、コールスタックを表示する関数
function yjd_debug_print($show_all=false) {
	ob_start();
	debug_print_backtrace();
	$str = ob_get_clean();
	echo nl2br( $str );
	echo "<br />\r\n";

	//	ハイライトしたい環境変数はここに追加する。
	$high_light = array(
		"HTTP_HOST",
		"HTTPS",
		"SERVER_PORT",
		"REQUEST_FILENAME",
		"REQUEST_URI",
		"HTTP_X_SAKURA_FORWARDED_FOR"
	);
	
	//	表示したい環境変数のテーブルはここに追加する。
	$tables = array(
		'_SERVER' => $_SERVER,
		'_ENV' => $_ENV,
		'_GET' => $_GET,
		'_POST' => $_POST,
	);

	foreach( $tables as $tname => $table ) {
		foreach( $table as $key => $val ) {
			$show_key = $key;
			$is_high_light = in_array( $key, $high_light );
			if( $is_high_light ) {
				$show_key = "<strong>" . $key . "</strong>";
			}
			if( $show_all || $is_high_light ) {
				print( "\$${tname}['$show_key'] = $val<br/>\r\n");
			}
		}
		echo "<br />\r\n";
	}
}

yjd_debug_print(true);

?>
</body>
</html>

.htaccess

以下のような.htaccessを作成し、testディレクトリに配置します。

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^test\.php$ - [L]
RewriteRule ^echo$ /test/test.php?SERVER_PORT=%{SERVER_PORT}&ENV:HTTPS=%{ENV:HTTPS}&HTTP:X-Sakura-Forwarded-For=%{HTTP:X-Sakura-Forwarded-For} [L]
</IfModule>

ブラウザから「https://xxxx.sakura.ne.jp/test/echo」(xxxxは各位のユーザーID)にアクセスすると、4行目のRewriteRuleにより、各環境変数がGETメソッドのクエリーになります。

test.phpによる表示で$_GETの中を見ると、以下が確認できます。

  • %{SERVER_PORT}に’80’がセットされている。
  • %{ENV:HTTPS}に’on’がセットされている。
  • %{HTTP:X-Sakura-Forwarded-For}にリクエスト元のIPアドレスがセットされている。

PHP

既に前節での表示で、PHPの環境変数$_SERVERと$_ENVが確認できます。

  • $_SERVER[‘SERVER_PORT’]及び$_ENV[‘SERVER_PORT’]に’80’がセットされている。
  • $_SERVER[‘HTTP_X_SAKURA_FORWARDED_FOR’]及び$_ENV[‘HTTP_X_SAKURA_FORWARDED_FOR’]にリクエスト元のIPアドレスがセットされている。
  • $_SERVER[‘HTTPS’]及び$_ENV[‘HTTPS’]はセットされていない。

次にブラウザから「https://xxxx.sakura.ne.jp/test/test.php」(xxxxは各位のユーザーID)にアクセスしてみます。すると以下が確認できます。

  • $_SERVER[‘HTTPS’]及び$_ENV[‘HTTPS’]に、’on’がセットされている。

このアクセスは、先の.htaccessの3行目のRewriteRuleで、書き換え無しにtest.phpが呼び出されます。この場合は環境変数HTTPSがセットされるようです。(.htaccessにRewriteRuleを書かない場合も同様です。)

しかし先の「echo」へのリクエストは、4行目のRewriteRuleでtest.phpに書き換えられます。このことと環境変数HTTPSがセットされないことが関係していそうです。

この件をさくらインターネットさんに問い合わせていますが、未だ回答はありません。

PHPでの対処法

SERVER_PORTが評価に使えず、HTTPSが限定的であるとすると、HTTP_X_SAKURA_FORWARDED_FORを使う以外にありません。これに関してもさくらインターネットさんに問い合わせました。

>2. isset( $_SERVER[‘HTTP_X_SAKURA_FORWARDED_FOR’] )のような評価式で
>httpsアクセスかどうか判定することを推奨しますか?(本来の仕様と、
>今後の変更の可能性など鑑みて)

こちらにつきまして、禁止はしておりませんが推奨もしておりません。
現時点では計画はございませんが、今後仕様の変更が行われる
可能性はございます。

(2013年8月22日の回答)

WordPressの対処法

WordPressの動作には、.htaccessによる書き換えが大前提になっています。従ってさくらレンタルサーバの共有SSLでは、$_SERVER[‘HTTPS’]が’on’になりません。$_SERVER[‘SERVER_PORT’]も’80’なので、それらを評価しているWordPressの関数is_ssl()はSSL接続の場合も常にfalseを返します。

よって、Admin SSLのようなプラグインは正常動作しません。(リダイレクトループが発生します。)

またWordPress内の諸所でis_ssl()をコールしているので、他にも不具合が生じると考えられます。

その対処法は、wp-config.phpの、「/* 編集が必要なのはここまでです ! WordPress でブログをお楽しみください。 */」の前に以下を記述します。

if( isset($_SERVER['HTTP_X_SAKURA_FORWARDED_FOR']) ) {
	$_SERVER['HTTPS'] = 'on';
	$_ENV['HTTPS'] = 'on';
}

至って簡単ですね。

(2017/02/01追記)ChromeやFirefoxが、パスワードのフォームがあるのにSSL/TLSにしていないと警告が出るようになったということで、SNI SSLの導入をされるかたも多いと思います。

上のコードも多くのブログで書かれているのですが、Wordpressのサイトを「www.hoge.com」のようなwww付きのURLで運営している場合は以下のようなコードにする必要があります。

if( isset($_SERVER['HTTP_X_SAKURA_FORWARDED_FOR']) ) {
    $_SERVER['HTTPS'] = 'on';
    if( substr($_SERVER['HTTP_HOST'], 0, 4)!=='www.') {
        $_SERVER['HTTP_HOST'] = 'www.'.$_SERVER['HTTP_HOST'];
    }
}

$_ENVへの設定は書いていませんが、お好みに応じて入れてください。(その上のコードでも$_ENVは必要ないんですがね。2013年の執筆時は保険のつもりでいれました。)

さくらのレンタルサーバーにて、「http://」でアクセスされた場合、$_SERVER[‘HTTP_HOST’]に格納されるホスト名(FQDN、以下同様)は、ユーザーがブラウザに入力したホスト名(「hoge.com」あるいは「www.hoge.com」)に一致します。

WordPressを「www.hoge.com」にて運営している場合、ホスト名が「hoge.com」のときはWordpressさんが「www.hoge.com」にリダイレクトします。ですので、サイトURLのホストはwww付に統一されます。(wwwなしの時も同様。)

しかし「https://」でアクセスされた場合、ユーザーがブラウザに「www.hoge.com」と入力したとしても、$_SERVER[‘HTTP_HOST’]は常に「hoge.com」になります。(しかしリダイレクトループが起きるのがトップページのみだったりするので、.htaccessのリライトとか他の要因もあるかもしれません。調べてません。)

結果、$_SERVER[‘HTTP_HOST’]のホスト名(hoge.com)が、Wordpressさんの記憶(www.hoge.com)と一致しないので、いつまでもリダイレクトするリダイレクトループになってしまいます。

上のパッチでは、httpsでホスト名の先頭が「www.」でないときに、「www.」を付けてあげています。if文で囲ってあるのは、ある日突然さくらさんの仕様が変わり、www付のホスト名が来るようになった時に、「www.www.hoge.com」のようになってリダイレクトループしないようにとの保険です。

ただ、レンタルサーバーでWordpressという環境、及び追記冒頭のSSL/TLSの需要を考えると、さくらさんがいつまでもこのようなパッチが必要な環境にしておくわけないだろ?と思います。

ですので、ここまで見た皆さんは昔に書かれたブログは信じず、公式サイトの情報、なければ最新の情報を(このページで検証したように)自身で確認されることを、切にお願いいたします。(2013年の執筆時に、需要がありそうなWordpressのパッチを一番最後にかいたのもそのような意図がありました。魚より釣り竿。以上、追記終わり。)

まとめ

さくらレンタルサーバーの共有SSLを利用する場合、以下の環境変数を評価に使います。

  • .htaccessでは%{ENV:HTTPS}が’on’かどうか。
  • PHPでは$_SERVER[‘HTTP_X_SAKURA_FORWARDED_FOR’]がセットされているかどうか。

WordPressを使う場合には、2点目を利用して対処します。

しかし環境変数HTTP_X_SAKURA_FORWARDED_FORの利用は、さくらさんから「禁止も推奨も」されていませんので、仕様変更に注意する必要があります。

(2017年2月10日追記:この記事とWordpressについての雑観を「さくらレンタルサーバーのSSL/STL化についてのエトセトラ」に書きました。よろしければご覧ください。)