ご挨拶、私は私の小さなプログラムを安全にして、潜在的な悪意のあるユーザーがサーバー上の機密ファイルを表示できないようにしたいと思っています。
$path = "/home/gsmcms/public_html/central/app/webroot/{$_GET['file']}";
if(file_exists($path)) {
echo file_get_contents($path);
} else {
header('HTTP/1.1 404 Not Found');
}
'../../../../../../etc/passwd'のような入力は問題になることはわかっていますが、他にどのような悪意のある入力を期待し、どのように行うべきか疑問に思っています。それらを防ぐために。
realpath() を使用すると、相対情報を含む可能性のあるすべてのパスを絶対パスに変換できます...次に、ダウンロードを許可する特定のサブディレクトリの下にパスがあることを確認できます。
ユーザーが提供できるすべての安全でないパスを予測しようとするのではなく、 basename を使用します。
OPによる解決策:
$baseDir = "/home/gsmcms/public_html/central/app/webroot/";
$path = realpath($baseDir . $_GET['file']);
// if baseDir isn't at the front 0==strpos, most likely hacking attempt
if(strpos($path, $baseDir) !== 0 || strpos($path, $baseDir) === false) {
die('Invalid Path');
} elseif(file_exists($path)) {
echo file_get_contents($path);
} else {
header('HTTP/1.1 404 Not Found');
echo "The requested file could not be found";
}
可能であれば、許可されたファイルの配列のようにwhitelistを使用し、それに対して入力を確認します。ユーザーが要求したファイルがそのリストに存在しない場合は、要求を拒否します。
ここには、追加の重大なセキュリティリスクがあります。このスクリプトは、サーバー側で処理することなく、ファイルのソースを出力ストリームに挿入します。これは、アクセス可能なファイルのすべてのソースコードがインターネットに漏洩することを意味します。
Realpathを使用している場合でも、使用する前にすべての「..」を削除する必要があります。そうしないと、攻撃者はブルートフォースでサーバーのディレクトリ構造全体を読み取る可能性があります。 "valid_folder /../../ test_if_this_folder_name_exists/valid_folder"-アプリケーションがこのパスを受け入れる場合、攻撃者はフォルダーが存在することを認識します。
すべてを取り除くには/. /..
または\。\..さまざまな環境がスラッシュを受け入れるため、すべてのスラッシュに変換します。これにより、パス入力にかなり安全なフィルターが提供されます。コードでは、万が一の場合に備えて、アクセスしたくない親ディレクトリと比較する必要があります。
$path = realpath(implode('/', array_map(function($value) {return trim($value, '.');}, explode('/', str_replace('\\', '/', $path)))));