• Записи 162
  • Теги 66
  • Комментарии 330

Компьютерное

Безопасное скачивание с сервера с сохранением имен файлов

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


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


И оказалось, что эту проблему очень легко можно решить следующим образом: при закачке для каждого файла генерируется номер, под которым он сохраняется в базу, и уникальный ключ (MD5-хеш от ряда параметров и случайного числа). Файл сохраняется под именем номер-ключ.dat, и на него дается ссылка вот такого вида: /files/номер-ключ/имя_файла_при_загрузке. А дальше с помощью mod_rewrite задается следующее правило:


RewriteRule ^downloads/(\d+\-[0-9a-z]+)/.+$ downloads/$1.dat [L]

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

4 комментария:

Нет
Gram
0

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

RewriteRule ^xfiles/foto/(\d+)\-([0-9a-z]+)\.jpg$ file.php?a=photo&ph=$1&key=$2
RewriteRule ^ index.php [L]

4X_Pro
0

Из-за последнего правила, оно все запросы на index.php переправляет, в в том числе и к файлам. Нужно либо в первую строку [L] добавить, либо второе правило как-то изменить.

Нет
Алексей
0

хм, так можно будет скачивать один файл под разными именами!

/files/12345/кошка.jpg
/files/12345/собака.jpg

ну, например, если файл был изначально загружен под именем "Untitled[1].jpg"

4X_Pro
0

В принципе, да. Но сделать проверку исходного имени средствами только Apache, без скриптов, не представляется возможным (ну или у меня знаний не хватает). А скрипт — это сразу и нагрузка на сервер выше, и нужно кучу всего предусмотреть: докачку, выдачу Last-Modified, ETag и т.д. Поэтому, на мой взгляд, в большинстве случаев можно смириться с такой особенностью.

Написать комментарий


Задать вопрос