Как загрузить картинку на сервер

от admin

Безопасная загрузка изображений на сервер. Часть первая

В данной статье демонстрируются основные уязвимости веб-приложений по загрузке файлов на сервер и способы их избежать. В статье приведены самые азы, в врят-ли она будет интересна профессионалам. Но тем неменее — это должен знать каждый PHP-разработчик.

Различные веб-приложения позволяют пользователям загружать файлы. Форумы позволяют пользователям загружать «аватары». Фотогалереи позволяют загружать фотографии. Социальные сети предоставляют возможности по загрузке изображений, видео, и т.д. Блоги позволяют загружать опять же аватарки и/или изображения.

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

Проводимые тесты показали, что многие веб-приложения имеют множество проблем с безопасностью. Эти «дыры» предоставляют злоумышленникам обширные возможности совершать несанкционированные действия, начиная с просмотра любого файла на сервере и закачивания выполнением произвольного кода. Эта статья рассказывает об основных «дырах» безопасности и способах их избежать.

Код примеров, приведенных в этой статье, могут быть загружены по адресу:
www.scanit.be/uploads/php-file-upload-examples.zip.

Если Вы хотите их использовать, пожалуйста удостоверьтесь, что сервер, который Вы используете, не доступен из Интернета или любых других публичных сетей. Примеры демонстрируют различные уязвимости, выполнение которых на доступном извне сервере может привести к опасным последствиям.

Обычная загрузка файла

Загрузка файлов, обычно состоит из двух независимых функций – принятие файлов от пользователя и показа файлов пользователю. Обе части могут быть источником уязвимостей. Давайте рассмотрим следующий код (upload1.php):

<?php
$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» ;
>
?>

* This source code was highlighted with Source Code Highlighter .

Обычно пользователи будут загружать файлы, используя подобную форму:

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

* This source code was highlighted with Source Code Highlighter .

Злоумышленник данную форму использовать не будет. Он может написать небольшой Perl-скрипт (возможно на любом языке – прим. преводчика), который будет эмулировать действия пользователя по загрузке файлов, дабы изменить отправляемые данные на свое усмотрение.

В данном случае загрузка содержит большую дыру безопасности: upload1.php позволяет пользователям загружать произвольные файлы в корень сайта. Злоумышленник может загрузить PHP-файл, который позволяет выполнять произвольные команды оболочки на сервере с привилегией процесса веб-сервера. Такой скрипт называется PHP-Shell. Вот самый простой пример подобного скрипта:

Если этот скрипт находится на сервере, то можно выполнить любую команду через запрос:
server/shell.php?command=any_Unix_shell_command

Более продвинутые PHP-shell могут быть найдены в Интернете. Они могут загружать произвольные файлы, выполнять запросы SQL, и т.д.

Исходник Perl, показанный ниже, загружает PHP-Shell на сервер, используя upload1.php:

#!/usr/bin/perl
use LWP; # we are using libwwwperl
use HTTP::Request::Common;
$ua = $ua = LWP::UserAgent-> new ;
$res = $ua->request(POST ‘http://localhost/upload1.php’ ,
Content_Type => ‘form-data’ ,
Content => [userfile => [ «shell.php» , «shell.php» ],],);

print $res->as_string();

* This source code was highlighted with Source Code Highlighter .

Этот скрипт использует libwwwperl, который является удобной библиотекой Perl, эмулирующей HTTP-клиента.

И вот что случится при выполнении этого скрипта:

После того, как мы загрузили shell-скрипт, можно спокойно выполнить команду:

cURL – command-line клиент HTTP, доступный на Unix и Windows. Это очень полезный инструмент для того, чтобы проверить веб-приложения. cURL может быть загружен от curl.haxx.se

Проверка Content-Type

Приведенный выше пример редко когда имеет место. В большинстве случаев программисты используют простые проверки, чтобы пользователи загружали файлы строго определенного типа. Например, используя заголовок Content-Type:

Пример 2 (upload2.php):

<?php
if ($_FILES[ ‘userfile’ ][ ‘type’ ] != «image/gif» ) <
echo «Sorry, we only allow uploading GIF images» ;
exit;
>
$uploaddir = ‘uploads/’ ;
$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» ;
>
?>

* This source code was highlighted with Source Code Highlighter .

В этом случае, если злоумышленник только попытается загрузить shell.php, наш код будет проверять MIME-тип загружаемого файла в запросе и отсеивать ненужное.

Пока неплохо. К сожалению, есть способ обойти эту защиту, потому что проверяемый MIME-тип приходит вместе с запросом. В запросе выше он установлен как «text/plain» (его устанавливает браузер – прим. переводчика). Ничего не мешает злоумышленнику установить его в «image/gif», поскольку с помощью эмуляции клиента он полностью управляет запросом, который посылает (upload2.pl):

#!/usr/bin/perl
#
use LWP;
use HTTP::Request::Common;
$ua = $ua = LWP::UserAgent-> new ;;
$res = $ua->request(POST ‘http://localhost/upload2.php’ ,
Content_Type => ‘form-data’ ,
Content => [userfile => [ «shell.php» , «shell.php» , «Content-Type» => «image/gif» ],],);

* This source code was highlighted with Source Code Highlighter .

И вот что получится.

В итоге, наш upload2.pl подделывает заголовок Content-Type, заставляя сервер принять файл.

Проверка содержания файла изображения

Вместо того, чтобы доверять заголовку Content-Type, разработчик PHP мог бы проверять фактическое содержание загруженного файла, чтобы удостовериться, что это действительно изображение. Функция PHP getimagesize() часто используется для этого. Она берет имя файла как аргумент и возвращает массив размеров и типа изображения. Рассмотрим пример upload3.php ниже.

<?php
$imageinfo = getimagesize($_FILES[ ‘userfile’ ][ ‘tmp_name’ ]);
if ($imageinfo[ ‘mime’ ] != ‘image/gif’ && $imageinfo[ ‘mime’ ] != ‘image/jpeg’ ) <
echo «Sorry, we only accept GIF and JPEG images\n» ;
exit;
>

$uploaddir = ‘uploads/’ ;
$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» ;
>
?>

* This source code was highlighted with Source Code Highlighter .

Теперь, если нападавший попытается загрузить shell.php, даже если он установит заголовок Content-Type в «image/gif», то upload3.php все равно выдаст ошибку.

Можно подумать, что теперь мы можем пребывать в уверенности, что будут загружаться только файлы GIF или JPEG. К сожалению, это не так. Файл может быть действительно в формате GIF или JPEG, и в то же время PHP-скриптом. Большинство форматов изображения позволяет внести в изображение текстовые метаданные. Возможно создать совершенно корректное изображение, которое содержит некоторый код PHP в этих метаданных. Когда getimagesize() смотрит на файл, он воспримет это как корректный GIF или JPEG. Когда транслятор PHP смотрит на файл, он видит выполнимый код PHP в некотором двоичном «мусоре», который будет игнорирован. Типовой файл, названный crocus.gif содержится в примере (см. начало статьи). Подобное изображение может быть создано в любом графическом редакторе.

Итак, создадим perl-скрипт для загрузки нашей картинки:

#!/usr/bin/perl
#
use LWP;
use HTTP::Request::Common;
$ua = $ua = LWP::UserAgent-> new ;;
$res = $ua->request(POST ‘http://localhost/upload3.php’ ,
Content_Type => ‘form-data’ ,
Content => [userfile => [ «crocus.gif» , «crocus.php» , «Content-Type» => «image/gif» ], ],);

* This source code was highlighted with Source Code Highlighter .

Этот код берет файл crocus.gif и загружает это с названием crocus.php. Выполнение приведет к следующему:

Теперь нападавший может выполнить uploads/crocus.php и получить следущее:

Как видно, транслятор PHP игнорирует двоичные данные в начале изображения и выполняет последовательность «<? phpinfo() ?>» в комментарии GIF.

Проверка расширения загружаемого файла

Читатель этой статьи мог бы задаться вопросом, почему мы просто не проверяем расширение загруженного файла? Если мы не позволим загружать файлы *.php, то сервер никогда не сможет выполнить этот файл как скрипт. Давайте рассмотрим и этот подход.

Мы можем сделать черный список расширений файла и проверить имя загружаемого файла, игнорируя загрузку файла с выполняемыми расширениями (upload4.php):

<?php
$blacklist = array( «.php» , «.phtml» , «.php3» , «.php4» );
foreach ($blacklist as $item) <
if (preg_match( «/$item\$/i» , $_FILES[ ‘userfile’ ][ ‘name’ ])) <
echo «We do not allow uploading PHP files\n» ;
exit;
>
>

$uploaddir = ‘uploads/’ ;
$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» ;
>
?>

* This source code was highlighted with Source Code Highlighter .

Выражение preg_match («/$item\$/i», $_FILES[‘userfile’][‘name’]) соответствует имени файла, определенному пользователем в массиве черного списка. Модификатор «i» говорит, что наше выражение регистронезависимое. Если расширение файла соответствует одному из пунктов в черном списке, файл загружен не будет.

Если мы пытаемся загрузить файл c расширением .php, это приведет к ошибке:

Если мы загружаем файл с расширением .gif, то оно будет загружено:

Теперь, если мы запросим загруженный файл, то он не будет выполнен сервером:

image

Комментарии переводчика:
В случае загрузки картинок самым лучшим способом являются не указанные действия, а сохранение файла с расширением, которое получается в результате выполнения функции getimagesize(). В большинстве случаев именно так и происходит. Стоит добавить, что желательно сделать приведение файла к конкретному формату, например jpeg. При приведении метаданные картинки (насколько мне известно) потеряются, обеспечив практически гарантируемую безопастность.

Наличие в загрузке файлов с расширением типа .php нужно проверять вообще в начале работы сайта, и если они есть сразу же их отбрасывать.

Загрузка изображений с превью AJAX + PHP + MySQL

В данной статье представлена упрощенная реализация загрузки изображений с превью через AJAX с сохранением в базу данных MySQL, а также дальнейший их вывод на примере модуля отзывов.

Читать:
Как определить переменную в маткаде

В примерах используется следующая структура файлов и директорий, находящихся в корне сайта:

Первое что понадобится: HTML форма и JS скрипт, который после выбора одного или несколькольких файлов отправит их на upload_image.php через AJAX.

index.php

CSS-стили для формы и вывода загруженных файлов:

Файлы отправляются на сервер до отправки основной формы (возможно пользователь вовсе её не отправит), поэтому PHP-скрипт сохранит полученные файлы во временную директорию /uploads/tmp/ с новым именем и создаст картинку-превью с префиксом «thumb» в конце названия файла, далее вернёт контент для вставки обратно в форму в формате JSON.

В целях безопасности, во временной директории /uploads/ должно быть отключено выполнение PHP-скриптов и выключен листинг каталогов.

Тек же временную директорию /uploads/tmp/ будет нужно периодически очищать от старых файлов.

Скрипт upload_image.php

Пример ответа AJAX запроса в случаи успешной загрузки файла:

Полученный из AJAX запроса контент вставляется в конец дива id="js-file-list" с помощью jQuery метода append() .

Скрытое поле «images» передает названия загруженных файлов следующему скрипту для сохранения в базе данных.

Загрузка изображений в папку на сервер и помещение информации в базу данных

Здравствуйте. Как можно сделать загрузку изображений со страницы сайта на сервер в определённую папку, и чтобы название файла заносилось в базу данных?

— В файле, который должен лежать в корне сайта, чтобы относительно этого файла правильно загружать в папку изображений от корня сайта.

— Пример отправки файла

— Обработчик для формы

Отложим в сторону всякие проверки, их вы сделаете сами и какие хотите (и файл ли это, и доступные расширения файлов, и прочее). Вам надо определиться, с каким именем будете сохранять файл, т.к. если его не переименовать, то может случиться так, что будет загружен файл с таким же именем, как у файла загруженного раньше. Это приведет к перезаписи существующего файла. Для примера, будем задавать новое имя в зависимости с текущей меткой времени Unix. Теперь к сути:

P.S. Поле файла в форме для моего примера, должно иметь атрибут name=»myfile». Замените на своё значение, соответственно изменив в глобальной переменной $_FILES[‘myfile’]

Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.3.11.43304

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Как загрузить файлы на веб-сервер

Данная статья покажет, как можно опубликовать сайт в Интернет с помощью инструментов передачи файлов(file transfer tools).

Необходимые знания: Вы должны знать что такое веб-сервер и как работают доменные имена. Также вы должны знать, как установить базовую среду и как написать простую веб-страницу.
Цель: Научиться передавать файлы на сервер используя различные доступные инструменты передачи файлов(file transfer tools).

Сводка

Если вы создали простую веб-страницу (для примера смотрите Основы HTML), вы, вероятно, захотите отобразить её онлайн, на веб-сервере. В данной статье мы обсудим как сделать это, используя различные доступные настройки, такие как SFTP клиенты, RSync и GitHub.

SFTP (Безопасный Протокол Передачи Файлов)

Существуют различные варианты SFTP клиентов. В нашем примере мы будем использовать FileZilla, тк он бесплатен и подходит для Windows, macOS и Linux. Чтобы установить менеджер перейдите на страницу загрузки FileZilla downloads page, нажмите на кнопку загрузки, затем установите пакет из установочного файла обычным способом.

Примечание: Конечно, есть много других вариантов. Смотрите Publishing tools для других способов.

Откройте приложение FileZilla; вы должны увидеть что-то вроде этого:

Вход в систему

В этом примере мы предположим, что наш хостинг-провайдер (сервис, на котором находится наш HTTP веб сервер) является фиктивной компанией «Example Hosting Provider», чьи URL адреса выглядят следующим образом: mypersonalwebsite.examplehostingprovider.net .

Сейчас мы создали аккаунт и получили от хостинг-провайдера следующую информацию:

  • SFTP сервер: sftp://demozilla.examplehostingprovider.net
  • Имя пользователя: demozilla
  • Пароль: quickbrownfox
  • Порт: 5548
  • Для публикации в интернет, поместите ваши файлы в папку Public/htdocs .

Давайте сначала посмотрим на http://demozilla.examplehostingprovider.net/ — как вы можете видеть, то здесь пока ничего нет:

Our demozilla personal website, seen in a browser: it

Примечание: В зависимости от вашего хостинг-провайдера, когда вы впервые заходите на свой веб-адрес, большую часть времени вы будете видеть страницу, на которой написано что-то вроде этого: “This website is hosted by [Hosting Service].”

Чтобы подключить SFTP клиент к удалённому серверу, выполните следующие действия:

  1. Выберите File > Site Manager. в главном меню.
  2. В окне Site Manager, нажмите кнопку New Site, затем введите название сайта как demozilla в предоставленном месте.
  3. Укажите SFTP-сервер вашего хоста в предоставленном поле: Host.
  4. В раскрывающемся списке Logon Type: выберите Normal, затем введите предоставленные имя пользователя и пароль в соответствующие поля.
  5. Введите правильный порт и другую информацию.

Ваше окно должно выглядеть как показано ниже:

Теперь нажмите Connect для подключения к SFTP-серверу.

Примечание: Убедитесь, что ваш хостинг-провайдер предлагает SFTP (безопасный FTP) подключение к вашему хостинговому пространству. FTP по своей сути небезопасен, и вам не следует его использовать.

Здесь и там: локальный и удалённый просмотр

После подключения ваш экран должен выглядеть примерно так (мы подключились к нашему собственному примеру, чтобы дать вам представление):

Давайте посмотрим, что вы видите:

  • По центру левой панели вы можете видеть локальные файлы. Перейдите в каталог, в котором вы храните свой веб-сайт (например, mdn ).
  • По центру правой панели вы увидеть удалённые файлы. Мы вошли в наш удалённый корень FTP (в данном случае: users/demozilla )
  • Вы можете пока игнорировать нижнюю и верхнюю панели. Соответственно, это журнал сообщений, показывающий состояние соединения между вашим компьютером и SFTP-сервером, и журнал в реальном времени каждого взаимодействия между вашим SFTP-клиентом и сервером.

Загрузка на сервер

Наш пример инструкций для хостинга указывает нам следующее: «Чтобы опубликовать в Интернете, поместите свои файлы в каталог: Public/htdocs .» Вам нужно перейти в указанный каталог на правой панели. Этот каталог фактически является корнем вашего веб-сайта, где находятся ваши index.html , откуда ваши файл и другие активы будут отправлены.

После того, как вы нашли правильный удалённый каталог для размещения файлов, чтобы загрузить файлы на сервер, вам необходимо переместить их с левой панели на правую.

Как узнать, что они online?

Пока все хорошо, но действительно ли файлы в сети? Вы можете перепроверить, перейдя на ваш сайт (например, http://demozilla.examplehostingprovider.net/ ) в вашем браузере:

Here we go: our website is live!

И вуаля! Наш сайт работает!

Rsync

Rsync (en-US) is a local-to-remote file synchronizing tool, which is generally available on most Unix-based systems (like macOS and Linux), but Windows versions exist too.

It is seen as a more advanced tool than SFTP, beause by default it is used on the command line. A basic command looks like so:

  • -options is a dash followed by a one or more letters, for example -v for verbose error messages, and -b to make backups. You can see the full list at the rsync man page (search for «Options summary»).
  • SOURCE is the path to the local file or directory that you want to copy files over from.
  • user@ is the credentials of the user on the remote server you want to copy files over to.
  • x.x.x.x is the IP address of the remote server.
  • DESTINATION is the path to the location you want to copy your directory or files to on the remote server.

You’d need to get such details from your hosting provider.

Of course, it is a good idea to use a secure connection, like with FTP. In the case of Rsync, you specify SSH details to make the connection over SSH, using the -e option. For example:

You can find more details of what is needed at How To Copy Files With Rsync Over SSH.

Rsync GUI tools

As with other command line tools, GUI tools also exist for Rsync, for those who are not as comfortable with using the command line. Acrosync is one such tool, and it is available for Windows and macOS.

Again, you would have to get the connection credentials from your hosting provider, but this way you’d have a GUI to enter them in.

GitHub

GitHub allows you to publish websites via GitHub pages (gh-pages).

We’ve covered the basics of using this in the Publishing your website article from our Getting started with the Web guide, so we aren’t going to repeat it all here.

However, it is worth knowing that you can also host a website on GitHub, but use a custom domain with it. See Using a custom domain with GitHub Pages for a detailed guide.

Other methods to upload files

The FTP protocol is one well-known method for publishing a website, but not the only one. Here are a few other possibilities:

Похожие статьи