Проверка имени файла на безопасность
Понедельник, 28 января, 2008Если в работе скрипта производится работа с файлом, имя которого получается из параметров HTTP-запроса, то совершенно очевидно, что такое имя файла необходимо проверять на наличие небезопасных символов.
Таковыми в частности являются:
/ или \ в начале имени может позволить обратиться к произвольному месту в файловой системе (если не указан текущий путь, это позволит открывать файлы в любом месте файловой системы, а не только ниже текущего каталога);
.. (две точки) — позволит подняться в каталог более высокого уровня и открыть файл там;
~ (тильда) — если интерпретатор выполняется от реального пользователя, а не от nobody (т.е. PHP запускается как CGI), позволяет открыть файл в его родительском каталоге;
` (обратный апостроф) — в некоторых ситуациях может позволить выполнить внешнюю команду на сервере;
://(часть, отделяющая протокол в URL от доменного имени) — при разрешенном подключении внешних файлов позволит загрузить и выполнить произвольный PHP-код.
Кроме того, ряд символов может привести к созданию нечитаемых/неудаляемых файлов, вызывать ошибку при записи или ошибку в HTML при формировании ссылки, поэтому их тоже желательно фильтровать. К таким символам относятся: двоеточие (:), точка с запятой (;), запятая (,), кавычки (”), апостроф (’), амперсанд (&), символы больше и меньше (<>).
В результате получаем следющую процедуру проверки:
function check_name( $filename) {
$result=(substr($filename,0,1)!='/' && substr($filename,0,1)!='\\');
if ($result) {
$test=array('..','://','~','`','\'','"',':',';',',','&','>','<');
for ($i=0, $count=count($test); $i<$count && $result; $i++) $result=(strpos($filename,$test[$i])===false);
}
return $result;
}
Кроме того, при загрузке файла имеет смысл сохранять его с таким именем, чтобы пользователь не мог его угадать (лучше всего для этой цели подходит MD5-хеш от имени + размера + времени загрузки + случайного значения), и не давать возможности узнать имя файла из URL ссылки для его скачивания/просмотра (т.е. если данные о загруженном файле хранятся в таблице БД, то скрипту для скачивания передавать номер этого файла в таблице, а не его имя).