レガシーwebアプリケーションを、ファイアウォールの内側で利用する
2011年3月9日
古くなったwebアプリケーションは、既知の脆弱性がそのまま放置されているようなケースが良くある。こうなると危なくてもう使えない(イントラネットで使うようなケースは別)。
そういったアプリケーションのすべての機能ではなく、一部の機能だけ使いたいというようなことは良くあるだろう。そういう場合、その一部の機能を担うための情報だけサニタイズして与えれば、問題なく使えるはずである。
使用中のwebページでそういったことに相当するケースがあったので、対処してみた。
PHPで書かれた古いwebアプリケーションが、/legacy/というURIにインストールしてあるとする。
1)まず、このレガシーアプリケーションへの直接のアクセスを遮断しなければならない。ここでは、BASIC認証を用いて、遮断する。.htaccessと.htpasswdを適当に設定して、アクセスするにはユーザー名とパスワードを入力しなければならないようにしておく。
2)ディレクトリ名を、第三者に類推できないようなものに変更する。ここでは、/xxxx_legacy/に変更したとする。
3)セキュリティーに関係の無い静的ファイルを、元のディレクトリ、/legacy/にコピーするか移動するかする。
4)/legacy/index.phpなど、動的ページ作成に必要なPHPファイルを、この記事の最後に書いたコードを参考にして作成する。ファイアーウォール機能はこのPHPファイルが担うことになる。
5)/xxxx_legacy/に移動したwebアプリケーションの設定を、これが適切に動くように修正する。場合によっては、スクリプトの先頭で$_SERVER['REQUEST_URI']を書き換えるなどの荒行事が必要になる場合もある。
これで終了である。元のレガシーアプリケーションへは直接アクセスせず、別個に作成したPHPを介してのアクセスになるため、既知の脆弱性があっても影響を受けることは無い。ただし、ファイアウォール部分のコードは当然ながら慎重に書かなければならない。
「www.example.com」「username」「password」の部分は、個々の設定に応じて書き換えること。
そういったアプリケーションのすべての機能ではなく、一部の機能だけ使いたいというようなことは良くあるだろう。そういう場合、その一部の機能を担うための情報だけサニタイズして与えれば、問題なく使えるはずである。
使用中のwebページでそういったことに相当するケースがあったので、対処してみた。
PHPで書かれた古いwebアプリケーションが、/legacy/というURIにインストールしてあるとする。
1)まず、このレガシーアプリケーションへの直接のアクセスを遮断しなければならない。ここでは、BASIC認証を用いて、遮断する。.htaccessと.htpasswdを適当に設定して、アクセスするにはユーザー名とパスワードを入力しなければならないようにしておく。
2)ディレクトリ名を、第三者に類推できないようなものに変更する。ここでは、/xxxx_legacy/に変更したとする。
3)セキュリティーに関係の無い静的ファイルを、元のディレクトリ、/legacy/にコピーするか移動するかする。
4)/legacy/index.phpなど、動的ページ作成に必要なPHPファイルを、この記事の最後に書いたコードを参考にして作成する。ファイアーウォール機能はこのPHPファイルが担うことになる。
5)/xxxx_legacy/に移動したwebアプリケーションの設定を、これが適切に動くように修正する。場合によっては、スクリプトの先頭で$_SERVER['REQUEST_URI']を書き換えるなどの荒行事が必要になる場合もある。
これで終了である。元のレガシーアプリケーションへは直接アクセスせず、別個に作成したPHPを介してのアクセスになるため、既知の脆弱性があっても影響を受けることは無い。ただし、ファイアウォール部分のコードは当然ながら慎重に書かなければならない。
<?php // Check the URI $uri=$_SERVER['REQUEST_URI']; ここにファイアウォール部分のコードを書き、安全な$uriを作成する。 /legacy/を/xxxx_legacy/に書き換えるなどの措置を取る。 http_request('www.example.com',$uri,'username','password'); function http_request($server,$uri,$user=false,$passwd=false){ // Sanitize the inputs $server=preg_replace('/[^a-zA-Z0-9\-\.]+/','',$server); $uri=preg_replace('/[\r\n\x00]+/','',$uri); // Get the socket $errno=$errstr=false; $socket=@fsockopen($server,80,$errno,$errstr,30); stream_set_blocking($socket,1); if (!$socket) { echo '<html><body>'.htmlspecialchars("$errstr ($errno)").'</body></html>'; exit; } // Prepare the request $request = "GET $uri HTTP/1.0\r\n"; $request .= "Host: $server\r\n"; if ($user!==false) $request .= "Authorization: Basic ".base64_encode("$user:$passwd")."\r\n"; $request .= "Connection: Close\r\n\r\n"; // Connect to server fwrite($socket, $request); $ret=''; while (!feof($socket)) { $ret.=fread($socket,1024); } fclose($socket); $i=strpos($ret,"\r\n\r\n"); if ($i!==false) { $header=substr($ret,0,$i); foreach(explode("\r\n",$header) as $line){ header($line); } $ret=substr($ret,$i+4); } echo $ret; }
「www.example.com」「username」「password」の部分は、個々の設定に応じて書き換えること。