セキュリティー

レガシー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を介してのアクセスになるため、既知の脆弱性があっても影響を受けることは無い。ただし、ファイアウォール部分のコードは当然ながら慎重に書かなければならない。

<?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」の部分は、個々の設定に応じて書き換えること。

コメント

コメントはありません

コメント送信