PHPセキュリティ対策:SSL通信を行う

(1/1)
サーバ間で重要なデータのやり取りを行う場合は、機密性(Confidentiality)完全性(Integrity) を確保するため、SSL通信を用いることが多い。
今回は、PHPでSSL通信を行う方法を紹介する。

(2022年6月27日)FastCGIで正常動作しない不具合を修正
(2022年5月21日)大幅改訂,SSL検証サイト変更,PHP8対応

目次

サンプル・プログラムの実行例

PHPセキュリティ対策:SSL通信を行う

サンプル・プログラム

圧縮ファイルの内容
curl_ssl.phpサンプル・プログラム本体。
pahooInputData.phpデータ入力に関わる関数群。
使い方は「PHPでGET/POSTでフォームから値を受け取る」「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。

PHPでSSL通信を行う方法

PHPでSSL(https)通信を行うには、 fsockopen 、 pfsockopen 、 file_get_contents 、 fopen 、 stream_socket_client  といった関数を用いて実装できるのだが、いずれもラッパとしてSSL通信がサポートされていることが前提だ。 phpinfo で、Registerd PHP Stream を使って確認することができる。。
SSL通信の場合、具体的にはOpenSSLがインストールされている必要がある。PHP5以降ではモジュール組み込みが可能だが、PHP 4.3.0以降では静的にコンパイルされ組み込まれている必要がある。このため、レンタルサーバなどリコンパイルが望めない環境では利用できない。

そこで今回は、PHP4.xでもモジュールを追加するだけでSSL通信が可能になるcURL, Client URL Library 関数を利用することにする。

cURL関数の準備

cURL関数とは、Daniel Stenbergにより開発されたライブラリ libcurl をサポー トする関数群である。PHP 4.0.2で追加された。
libcurl は現在、http, https, ftp, gopher, telnet, dict, file, ldap プロトコルをサポートしている。

cURL関数を利用するには、--with-curl[=DIR] を付けて PHP をコンパイルしておく。ここで、DIR は、ディレクトリ lib および include を有するディレクトリの場所である。
ディレクトリ "include" には、"curl" という名前のフォルダがある必要があり、そのフォルダにはファイル easy.h および curl.h がある必要がある。また、libcurl.a という名前のファイルがディレクトリ "lib" にある必要がある。
PHP 4.3.0 以降では、URL ストリームで cURL を使用するよう PHP を 設定するために --with-curlwrappers を指定できるようになった。

Windows環境では、libeay32.dll および ssleay32.dll を PATH の通ったディレクトリ(一般的に \windows\system32\)に配置する必要がある。これらの dll はPHPのパッケージの dlls に含まれている。

次に、php.iniextension=php_curl を有効にする。

PHPを再起動すれば、cURL関数群が利用できるようになる。

解説:SSLサイトからテキストを取得

 107: /**
 108:  * SSLサイトからテキストを取得
 109:  * @param   string $url     サイトURL
 110:  * @param   string $errmsg  エラーメッセージ
 111:  * @return  string テキスト
 112: */
 113: function getSSLsite($url, &$errmsg) {
 114:     //SSLが利用できるかどうか調べる
 115:     $arr = stream_get_transports();
 116:     $errmsg = 'PHP処理系がSSL通信に対応していない';
 117:     foreach ($arr as $val) {
 118:         if (preg_match('/ssl/i', $val> 0) {
 119:             $errmsg = '';
 120:             break;
 121:         }
 122:     }
 123:     if ($errmsg !'')      return FALSE;
 124: 
 125:     //cURL関数が利用できるかどうか調べる
 126:     $errmsg = 'PHP処理系がcURL関数に対応していない';
 127:     if (function_exists('curl_init')) {
 128:         $errmsg = '';
 129:     }
 130:     if ($errmsg !'')      return FALSE;
 131: 
 132:     //SSLサイトからテキストを取得
 133:     $curl = curl_init($url);
 134:     // curl_setopt($curl, CURLOPT_SSLVERSION, 3);       //SSLv3脆弱性対応
 135:     curl_setopt($curl, CURLOPT_URL, $url);
 136:     curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);   //結果を文字列で返す
 137:     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);  //サーバ証明書検証をスキップ
 138:     curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);  //  同上
 139:     curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);   //リダイレクトをたどる
 140:     curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE);      //  同上
 141:     curl_setopt($curl, CURLOPT_TIMEOUT, 30);            //タイムアウト時間
 142: 
 143:     $result = curl_exec($curl);
 144:     curl_close($curl);
 145: 
 146:     //取得テキストを加工
 147:     $str = strip_tags($result);
 148:     $outstr = "";
 149:     $tok = strtok($str, "\n");
 150:     while ($tok !FALSE) {
 151:         $ss = trim($tok);
 152:         if ($ss !'') {
 153:             $outstr .$tok . '<br />';
 154:         }
 155:         $tok = strtok("\n");
 156:     }
 157: 
 158:     return $outstr;
 159: }

ユーザー関数 getSSLsite は、SSLサイトからコンテンツを取得する。

まず、PHP処理系がSSL通信に対応しているかどうか、組み込み関数  stream_get_transports  を使って調べる。
次に、PHP処理系がcURL関数をサポートしているかどうか、組み込み関数  function_exists  を使って調べる。

cURL関数の使い方は簡単である。
まず、関数  curl_init  を使って cURL セッションを初期化する。戻り値はリソースIDである。
次に、関数  curl_setopt  を使って、通信用の各種オプションを設定していく。
一般的には、CURLOPT_URL,CURLOPT_RETURNTRANSFER の2つを指定する。
サーバ証明書の検証を求めてくるようなサイトに対しては、これをスキップするため、CURLOPT_SSL_VERIFYPEER, CURLOPT_SSL_VERIFYHOST の2つをFALSEにする。
なお、CURLOPT_SSLVERSIONについてはSSLv2、SSLv3の既知の脆弱性に対応するため、指定を行わない方が無難だ。

関数  curl_exec  によってSSL通信を実施し、戻ってきたテキスト(サイト・コンテンツ)$result からHTMLタグや余分な改行を除き、変数 $outstr に格納して戻す。

WebAPIとSSL通信

サーバ間通信では、引き数を GET/POST で渡し、戻り値を XML で受け取る、いわゆるWebAPI をとることが多い。
cURL関数は GET/POST 渡しを行うことも簡単にできる。
また、戻り値のXMLは、DOM XML関数を使うか、SimpleXMLで処理するなら関数  simplexml_load_string  で $result を取り込めばいいだろう。

参考サイト

(この項おわり)
header