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

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

(2022年5月21日)大幅改訂,SSL検証サイト変更,PHP8対応

目次

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

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

サンプル・プログラム

圧縮ファイルの内容
curl_ssl.phpサンプル・プログラム本体。

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サイトからテキストを取得

0104: /**
0105:  * SSLサイトからテキストを取得
0106:  * @param   string $url     サイトURL
0107:  * @param   string $errmsg  エラーメッセージ
0108:  * @return  string テキスト
0109: */
0110: function getSSLsite($url, &$errmsg) {
0111:     //SSLが利用できるかどうか調べる
0112:     $arr = stream_get_transports();
0113:     $errmsg = 'PHP処理系がSSL通信に対応していない';
0114:     foreach ($arr as $val) {
0115:         if (preg_match('/ssl/i', $val) > 0) {
0116:             $errmsg = '';
0117:             break;
0118:         }
0119:     }
0120:     if ($errmsg != '')      return FALSE;
0121: 
0122:     //cURL関数が利用できるかどうか調べる
0123:     $errmsg = 'PHP処理系がcURL関数に対応していない';
0124:     if (function_exists('curl_init')) {
0125:         $errmsg = '';
0126:     }
0127:     if ($errmsg != '')      return FALSE;
0128: 
0129:     //SSLサイトからテキストを取得
0130:     $curl = curl_init($url);
0131:     // curl_setopt($curl, CURLOPT_SSLVERSION, 3);        //SSLv3脆弱性対応
0132:     curl_setopt($curlCURLOPT_URL$url);
0133:     curl_setopt($curlCURLOPT_RETURNTRANSFERtrue);    //結果を文字列で返す
0134:     curl_setopt($curlCURLOPT_SSL_VERIFYPEERFALSE);   //サーバ証明書検証をスキップ
0135:     curl_setopt($curlCURLOPT_SSL_VERIFYHOSTFALSE);   //  同上
0136:     curl_setopt($curlCURLOPT_FOLLOWLOCATIONTRUE);    //リダイレクトをたどる
0137:     curl_setopt($curlCURLOPT_AUTOREFERERTRUE);       //  同上
0138:     curl_setopt($curlCURLOPT_TIMEOUT, 30);         //タイムアウト時間
0139: 
0140:     $result = curl_exec($curl);
0141:     curl_close($curl);
0142: 
0143:     //取得テキストを加工
0144:     $str = strip_tags($result);
0145:     $outstr = "";
0146:     $tok = strtok($str, "\n");
0147:     while ($tok != FALSE) {
0148:         $ss = trim($tok);
0149:         if ($ss != '') {
0150:             $outstr .= $tok . '<br />';
0151:         }
0152:         $tok = strtok("\n");
0153:     }
0154: 
0155:     return $outstr;
0156: }

ユーザー関数 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