ラボ > PHP:セキュリティ関連

PHP パス・トラバーサル対策

ユーザーの入力した情報を元に指定したディレクトリの中にアクセスさせたいが、相対PATH指定だと親にもアクセスができるので、その対策

作成日:2020-01-31, 更新日:2020-01-31

基本

・パス・トラバーサル対策:ユーザーによる親階層のファイルへのアクセスを禁止したい

▼例えば・・・下記のようなディレクトリを削除させる処理

define('PATH_DOC', '/〇〇〇/〇〇〇');
$dir = PATH_DOC . '/' . $_POST['path'];
rmdir($dir);

▼「$_POST['path']」の値が・・・
・「hoge」などのディレクトリ名を期待→問題無い
・「../」などのような親を参照するような相対PATH→困る

対策1

手っ取り早くいくなら親を指定するような相対PATHの記述の「..」を認めなければいい

サンプル

・「..」だけのとき→消す
・「/..」or「../」→消す
・「hoge..xxx」とか変なファイル名→放置
・「.」「/」がエスケープされた「%2e」「%2f」→消す

function escPath($str){
  if ( $str=='..' || $str=='%2e%2e' ) {
    return '';
  }

  $ng_seed = array(
    '/..', '%2f%2e%2e',
    '../', '%2e%2e%2f',
  );
  return str_replace($ng_seed, '', $str);
}

define('PATH_DOC', '/〇〇〇/〇〇〇');
$dir = PATH_DOC . '/' . escPath($_POST['path']);
rmdir($dir);

※これだと親階層は削除されない。ただ対象PATHが見つからずに変なエラーになるかもしれない

対策2

・指定したディレクトリ配下じゃなければ認めない

サンプル

function chkPath($ori_path, $acs_path){
  if ( strpos($acs_path, $ori_path) !== 0 ) {
    // 指定外のパスになるならエラー
    return false;
  }
  return true;
}

define('PATH_DOC', '/〇〇〇/〇〇〇');
$dir  = realpath(PATH_DOC.'/'.$_POST['path']);
if ( !_p(PATH_DOC, $dir) ) {
  // 処理中止
  exit;
}
else {
  // 処理続行
  rmdir($dir);
}