HTTP_Request2によるクライアント接続

今度、ファイルアップロードを受けるサーバを立ち上げる必要ができた。簡単のためにサーバ側はPHPで記述する。そのサーバをテストする目的で、やはり簡単のためにクライアント側もPHPで記述することにした。

最初HTTP_Requestを使ってみたが、どうもdeprecatedのようで、HTTP_Request2を使えとのメッセージが出ていたので(どこで見たかは忘れた)、HTTP_Request2を使うことにした。

そこでHTTP_Request2を調べてみたが、Web上には余り情報がない。しかも、https接続に関して危険な誤りが多かったので、ここで情報開示する。

設定なし

最も簡単なアップロードスクリプトは以下のようになるだろう。

<?php
require_once "HTTP/Request2.php";
$url = "https://xxx.izumi-si.co.jp/server.php";
try {
	$req = new HTTP_Request2($url,HTTP_Request2::METHOD_POST);
	$req->setAuth("username","password");
	$req->addUpload("key","real_filepath","filename_on_server","mime_type");
	$result = $req->send();
	echo $result->getBody();
} catch(HTTP_Request2_Exception $e) {
	die($e->getMessage());
} catch (Exception $e) {
	die($e->getMessage());
}

ところが、セキュアサイトに接続すると以下のようなエラーが出る。

stream_socket_client(): Failed to enable crypto
stream_socket_client(): SSL operation failed with code 1.
OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

これは、証明書が検証できないというエラーである。

間違った対処法

これに対して、ネット上で多く見られた間違った情報は、次のような対処法である。

<?php
$req->setConfig(array(
	'ssl_verify_peer' => false,
));

確かにこれでエラーはなくなるが、これは根本的に間違っている。それは、この設定が「サーバ証明書を検証しない」ことを表すからであり、これではhttps接続の意義が半減する。

なお、これはHTTP_Request2の例だけでなく、Rubyパッケージの例などについても多く見られた誤りなので、注意されたい。一種のセキュリティーホールと言えなくはない危険な誤りである。

正しい対処法

正しい対処法は以下である。

<?php
$req->setConfig(array(
	'ssl_verify_peer' => true,
	'ssl_capath' => '/etc/ssl/certs',
));

これは、ルートCA証明書を保存したフォルダを設定するものだ。上記のパスはDebian Wheezyのものだが、opensslパッケージで作成される証明書のハッシュが収められたフォルダである。但し、このフォルダにCA証明書そのものが収められているとは限らないので、注意のこと。あくまでも、「証明書」ではなく「証明書のハッシュ」が保存されたフォルダを指定すること。

ssl_capath」を使用した実例がネット上に少なかったので、あえて開示した。