1

Topic: Скрипт загрузки файлов на сервер

Загрузка файлов, обычно состоит из двух независимых частей.  Давайте рассмотрим следующий код:

if (isset($_POST['load_file']))
{
   $uploaddir = 'uploads/'; // Relative path under webroot
   $uploadfile = $uploaddir . basename($_FILES['userfile']['name']);

   if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) 
  {
     echo "File is valid, and was successfully uploaded.\n";
   } else {
     echo "File uploading failed.\n";
   }
}

Многие используя подобную форму:

<form name="upload" action="" method="POST" ENCTYPE="multipart/form-data">
 Select the file to upload: <input type="file" name="userfile">
 <input type="submit" name="load_file" value="upload">
</form>

Но такой подход далеко не безопасный.

2

Re: Скрипт загрузки файлов на сервер

После успешной загрузки в массиве будут следующая информация:

[userfile] => Array
        (
            [name] => fr_fr.txt
            [type] => text/plain
            [tmp_name] => /tmp/phpWMPake
            [error] => 0
            [size] => 4572
        )

3

Re: Скрипт загрузки файлов на сервер

Предположим, что веб-приложение использует следующий код PHP для загрузки файлов (upload.php):

<?php
$target_path = "uploads/";
$target_path = $target_path . basename( $_FILES['uploadedfile']['name']);
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path))
{
    echo "The file ". basename( $_FILES['uploadedfile']['name']).
    " has been uploaded";
}
else
{
    echo "There was an error uploading the file, please try again!";
}
?>

Данный сценарий работает вместе со следующей HTML-формой:

<form enctype="multipart/form-data" action="uploader.php" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="100000" />
    Choose a file to upload: <input name="uploadedfile" type="file" /><br />
    <input type="submit" value="Upload File" />
</form>

Когда PHP принимает POST-запрос с типом кодировки "multipart/form-data", создается временный файл со случайным именем в директории для временных файлов (т.е. /var/tmp/php4vlktb). PHP также заполняет глобальный массив $_FILES информацией о загруженном файле:

$_FILES['uploadedfile']['name']: Оригинальное имя файла на компьютере клиента.
$_FILES['uploadedfile']['type']: MIME-тип файла.
$_FILES['uploadedfile']['size']: Размер файла в байтах.
$_FILES['uploadedfile']['tmp_name']: Временное имя загруженного файла, под которым он сохранен на сервере.

Функция PHP move_uploaded_file переместит временный файл по заданному пользователем пути. В данном случае путь для перемещения файла находится в пределах корневой директории веб-сервера. Следовательно, файл будет доступен при использовании строки URL, похожей на следующую: http://www.example.com/uploads/temp-uploads/uploadedfile.jpg.

В этом простом примере не накладывается ограничений на тип загружаемых файлов, поэтому взломщик может загрузить файл с вредоносным кодом PHP или .NET, что приведет к компрометации сервера. В таком случае взломщик может просто загрузить вредоносные сценарии c99 shell или r57 shell и получить контроль над сервером.

Однако, даже если в целях безопасности проверка расширения файла производится перед загрузкой, взломщик может также обойти ее, использовав нулевой символ %00. Все что требуется сделать, это выбрать файл PHP для загрузки, не нажимая на кнопку "Загрузить". Путь к выбранному для загрузки файлу будет отображен и для *NIX-систем будет выглядеть как /Users/username/exploit.php, а для Windows-систем как c:\exploit.php. На этом этапе нужно вручную добавить к строке нулевой символ с каким-либо последующим расширением изображения, например, /Users/username/exploit.php%00.jpg или c:\exploit.php%00.jpg.

После нажатия на кнопку "Загрузить" сервер проверит расширение, посчитает, что производится загрузка изображения и выведет сообщение, подобное следующему: "Спасибо за загрузку вашего изображения!". Как только файл будет загружен, появится возможность выполнения вредоносного кода на сервере.

Другим популярным способом защиты от исполнения загруженных файлов является запрет на исполнение сценариев в директории загрузок с помощью файла .htaccess. Стандартный файл .htaccess для этой цели должен содержать следующий код:

AddHandler cgi-script .php .php3 .php4 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi
Options -ExecCGI

Код, приведенный выше, использует список запрещенных расширений и не особенно безопасен сам по себе. Взломщик может просто обойти такие проверки, загрузив файл с названием .htaccess, содержащий код, подобный следующему:

AddType application/x-httpd-php .jpg

Эта строка указывает Apache, что необходимо исполнять файлы изображений с расширением .jpg так, как будто это сценарии PHP. Теперь взломщик может загрузить файл с расширением .jpg, содержащий код PHP. Так как загружаемые файлы могут перезаписывать и перезаписывают существующие, злоумышленники могут без лишних сложностей заменить файл .htaccess своей модифицированной версией, позволяющей исполнять определенные сценарии для последующей компрометации сервера.

4

Re: Скрипт загрузки файлов на сервер

Механизм загрузки файлов является ключевой функцией многих веб-приложений, а с учетом следующих мер предосторожности он может быть реализован максимально безопасно:

Не используйте заданных пользователями имен файлов в вашей системе. Наоборот, генерируйте свои непредсказуемые имена файлов. Подойдет имя в виде хэш-значения (md5/sha), так как его просто проверить (это просто строка шестнадцатеричных чисел). Возможно, к имени следует добавлять порядковый номер или время для предотвращения случайных коллизий.
В том случае, если нет возможности просмотра загружаемых файлов модератором, важно сделать возможной загрузку файлов только после прохождения аутентификации. В этом случае, по крайней мере, возможно отследить того, кто загрузил интересующий файл.
Следует фиксировать данные (такие, как время, IP-адрес клиента и имя пользователя) при загрузках файлов и наступлении других событий. Это поможет вам узнать, какие типы атак применялись против вашего сервера и были ли эти атаки успешными.
Если это возможно, следует также проверять загружаемые файлы на наличие вредоносного программного обеспечения; следует загружать файлы в директорию вне корневой директории веб-сервера.
Не стоит полагаться только на проверку загружаемых файлов на стороне клиента, так как этой проверки не достаточно. В идеальном случае следует реализовать проверку и на стороне клиента и на стороне сервера.

5

Re: Скрипт загрузки файлов на сервер

При загрузке файла в массиве $_FILES возвращается и размер файла и тип загружаемого файла. Так что достаточно задать переменную-массив с предполагаемыми форматами для загрузки и переменную с максимальным размером и проверять на соответствие этим значениям.

Например:

$types = array('image/gif', 'image/png', 'image/jpeg', 'image/pjpeg');
if (!in_array($_FILES['file']['type'], $types)){
     echo 'Недопустимый тип файла. Допустимо загружать только изображения: *.gif, *.png, *.jpg';
}

Аналогично с размером.

Для генерации уникального имени можно кодировать название файла в md5 с добавлением случайного значения в "хвост".

Например:

$file_name = md5($file_name).rand(999,100000);

Для получения имени файла (и отделения его расширения) можно сделать:

explode('.', $_FILES['file']['name'])

Последним значением полученного массива и будет расширение загруженного файла.

Для удаления файла используется unlink.

6

Re: Скрипт загрузки файлов на сервер

Вот полный скрипт:

<?
$max_image_width  = 380;
$max_image_height  = 600;
$max_image_size    = 64 * 1024;
$valid_types     =  array("gif","jpg", "png", "jpeg");

if (isset($_FILES["userfile"])) {
  if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
    $filename = $_FILES['userfile']['tmp_name'];
    $ext = substr($_FILES['userfile']['name'], 
      1 + strrpos($_FILES['userfile']['name'], "."));
    if (filesize($filename) > $max_image_size) {
      echo 'Error: File size > 64K.';
    } elseif (!in_array($ext, $valid_types)) {
      echo 'Error: Invalid file type.';
    } else {
       $size = GetImageSize($filename);
       if (($size) && ($size[0] < $max_image_width) 
        && ($size[1] < $max_image_height)) {
        if (@move_uploaded_file($filename, "/www/htdocs/upload/")) {
          echo 'File successful uploaded.';
        } else {
          echo 'Error: moving fie failed.';
        }
      } else {
        echo 'Error: invalid image properties.';
      }
    }
  } else {
    echo "Error: empty file.";
  }
} else {
  echo  '
  <form enctype="multipart/form-data" method="post"> 
  <input type="hidden" name="MAX_FILE_SIZE" value="64000"> 
  Send this file: <input name="userfile" type="file"> 
  <input type="submit" value="Send File"> 
  </form>';
}
?>

1

7

Re: Скрипт загрузки файлов на сервер

Большое спасибо!

PunBB developer

8

Re: Скрипт загрузки файлов на сервер

MIME (Multipurpose Internet Mail Extension, Многоцелевые расширения почты Интернета) — спецификация для передачи по сети файлов различного типа: изображений, музыки, текстов, видео, архивов и др. Указание MIME-типа используется в HTML обычно при передаче данных форм и вставки на страницу различных объектов.

Spoiler
Расширение файла  Тип данных
ai  application/postscript
aif  audio/aiff
aif  audio/x-aiff
aiff  audio/aiff
aiff  audio/x-aiff
ani  application/x-navi-animation
aos  application/x-nokia-9000-communicator-add-on-software
aps  application/mime
arc  application/octet-stream
arj  application/arj
arj  application/octet-stream
art  image/x-jg
asf  video/x-ms-asf
asm  text/x-asm
asp  text/asp
asx  application/x-mplayer2
asx  video/x-ms-asf
asx  video/x-ms-asf-plugin
au  audio/basic
au  audio/x-au
avi  application/x-troff-msvideo
avi  video/avi
avi  video/msvideo
avi  video/x-msvideo
bin  application/mac-binary
bin  application/macbinary
bin  application/octet-stream
bin  application/x-binary
bin  application/x-macbinary
bm  image/bmp
bmp  image/bmp
bmp  image/x-windows-bmp
boo  application/book
book  application/book
c  text/x-c
c++  text/plain
ccad  application/clariscad
class  application/java
class  application/java-byte-code
class  application/x-java-class
com  application/octet-stream
com  text/plain
conf  text/plain
cpp  text/x-c
cpt  application/mac-compactpro
cpt  application/x-compactpro
cpt  application/x-cpt
css  application/x-pointplus
css  text/css
dcr  application/x-director
def  text/plain
dif  video/x-dv
dir  application/x-director
dl  video/dl
dl  video/x-dl
doc  application/msword
dot  application/msword
drw  application/drafting
dvi  application/x-dvi
dwg  application/acad
dwg  image/vnd.dwg
dwg  image/x-dwg
dxf  application/dxf
dxf  image/vnd.dwg
dxf  image/x-dwg
dxr  application/x-director
exe  application/octet-stream
gif  image/gif
gz  application/x-compressed
gz  application/x-gzip
gzip  application/x-gzip
gzip  multipart/x-gzip
h  text/plain
h  text/x-h
hlp  application/hlp
hlp  application/x-helpfile
hlp  application/x-winhelp
htc  text/x-component
htm  text/html
html  text/html
htmls  text/html
htt  text/webviewhtml
ice  x-conference/x-cooltalk
ico  image/x-icon
inf  application/inf
jam  audio/x-jam
jav  text/plain
jav  text/x-java-source
java  text/plain
java  text/x-java-source
jcm  application/x-java-commerce
jfif  image/jpeg
jfif  image/pjpeg
jfif-tbnl  image/jpeg
jpe  image/jpeg
jpe  image/pjpeg
jpeg  image/jpeg
jpeg  image/pjpeg
jpg  image/jpeg
jpg  image/pjpeg
jps  image/x-jps
js  application/x-javascript
js  application/javascript
js  application/ecmascript
js  text/javascript
js  text/ecmascript
latex  application/x-latex
lha  application/lha
lha  application/octet-stream
lha  application/x-lha
lhx  application/octet-stream
list  text/plain
lsp  application/x-lisp
lsp  text/x-script.lisp
lst  text/plain
lzh  application/octet-stream
lzh  application/x-lzh
lzx  application/lzx
lzx  application/octet-stream
lzx  application/x-lzx
m3u  audio/x-mpequrl
man  application/x-troff-man
mid  application/x-midi
mid  audio/midi
mid  audio/x-mid
mid  audio/x-midi
mid  music/crescendo
mid  x-music/x-midi
midi  application/x-midi
midi  audio/midi
midi  audio/x-mid
midi  audio/x-midi
midi  music/crescendo
midi  x-music/x-midi
mod  audio/mod
mod  audio/x-mod
mov  video/quicktime
movie  video/x-sgi-movie
mp2  audio/mpeg
mp2  audio/x-mpeg
mp2  video/mpeg
mp2  video/x-mpeg
mp2  video/x-mpeq2a
mp3  audio/mpeg3
mp3  audio/x-mpeg-3
mp3  video/mpeg
mp3  video/x-mpeg
mp4  video/mp4
mpa  audio/mpeg
mpa  video/mpeg
mpeg  video/mpeg
mpg  audio/mpeg
mpg  video/mpeg
mpga  audio/mpeg
pas  text/pascal
pcl  application/vnd.hp-pcl
pcl  application/x-pcl
pct  image/x-pict
pcx  image/x-pcx
pdf  application/pdf
pic  image/pict
pict  image/pict
pl  text/plain
pl  text/x-script.perl
pm  image/x-xpixmap
pm  text/x-script.perl-module
pm4  application/x-pagemaker
pm5  application/x-pagemaker
png  image/png
pot  application/mspowerpoint
pot  application/vnd.ms-powerpoint
ppa  application/vnd.ms-powerpoint
pps  application/mspowerpoint
pps  application/vnd.ms-powerpoint
ppt  application/mspowerpoint
ppt  application/powerpoint
ppt  application/vnd.ms-powerpoint
ppt  application/x-mspowerpoint
ppz  application/mspowerpoint
ps  application/postscript
psd  application/octet-stream
pwz  application/vnd.ms-powerpoint
py  text/x-script.phyton
pyc  applicaiton/x-bytecode.python
qt  video/quicktime
qtif  image/x-quicktime
ra  audio/x-pn-realaudio
ra  audio/x-pn-realaudio-plugin
ra  audio/x-realaudio
ram  audio/x-pn-realaudio
rm  application/vnd.rn-realmedia
rm  audio/x-pn-realaudio
rpm  audio/x-pn-realaudio-plugin
rtf  application/rtf
rtf  application/x-rtf
rtf  text/richtext
rtx  application/rtf
rtx  text/richtext
rv  video/vnd.rn-realvideo
sgml  text/sgml
sgml  text/x-sgml
sh  application/x-bsh
sh  application/x-sh
sh  application/x-shar
sh  text/x-script.sh
shtml  text/html
shtml  text/x-server-parsed-html
ssi  text/x-server-parsed-html
tar  application/x-tar
tcl  application/x-tcl
tcl  text/x-script.tcl
text  application/plain
text  text/plain
tgz  application/gnutar
tgz  application/x-compressed
tif  image/tiff
tif  image/x-tiff
tiff  image/tiff
tiff  image/x-tiff
txt  text/plain
uri  text/uri-list
vcd  application/x-cdlink
vmd  application/vocaltec-media-desc
vrml  application/x-vrml
vrml  model/vrml
vrml  x-world/x-vrml
vsd  application/x-visio
vst  application/x-visio
vsw  application/x-visio
wav  audio/wav
wav  audio/x-wav
wmf  windows/metafile
xla  application/excel
xla  application/x-excel
xla  application/x-msexcel
xlb  application/excel
xlb  application/vnd.ms-excel
xlb  application/x-excel
xlc  application/excel
xlc  application/vnd.ms-excel
xlc  application/x-excel
xld  application/excel
xld  application/x-excel
xlk  application/excel
xlk  application/x-excel
xll  application/excel
xll  application/vnd.ms-excel
xll  application/x-excel
xlm  application/excel
xlm  application/vnd.ms-excel
xlm  application/x-excel
xls  application/excel
xls  application/vnd.ms-excel
xls  application/x-excel
xls  application/x-msexcel
xlt  application/excel
xlt  application/x-excel
xlv  application/excel
xlv  application/x-excel
xlw  application/excel
xlw  application/vnd.ms-excel
xlw  application/x-excel
xlw  application/x-msexcel
xm  audio/xm
xml  application/xml
xml  text/xml
z  application/x-compress
z  application/x-compressed
zip  application/x-compressed
zip  application/x-zip-compressed
zip  application/zip
zip  multipart/x-zip