Ограничение загрузки файлов

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

После совершения покупки клиент должен быть доставлен на страницу, содержащую ссылку для загрузки, а также получать электронные письма, содержащие ссылку для загрузки и электронную почту с информацией об учетной записи, которая будет создана для них (они также смогут загрузка с панели управления его учетной записи). Я пытаюсь выяснить, как я могу скрыть / скрыть местоположение файла на моем сервере, чтобы один человек, который его покупает, не мог просто скопировать и вставить прямую ссылку на файл в другом месте. Даже если я сделаю запрос на загрузку файла ссылкой в ​​формате http://example.com/blah/download/454643 , URL-адрес, который не соответствует фактическому местоположению файла, я думаю, что это все еще возможно найти файл на сервере? Я не слишком разбираюсь в том, как разрешается работать на моем сервере, и поэтому я спрашиваю. Заранее спасибо 🙂

В основном вы не предоставляете пользователям прямой URL-адрес файла. Разрешения на основе сервера здесь не имеют никакого отношения.

Скажем, у вас есть файл (ы), сохраненный в /data/files/file.pdf (хорошая практика для хранения файлов из вашего веб-корня). Вы можете предоставить пользователям ссылку для загрузки, которая выглядит как /download.php?auth=32

Когда пользователь нажимает на ссылку, download.php проверяет, проверена ли сессия / файл cookie, и если идентификатор загрузки действителен (в случае, если у вас есть время окончания срока действия загрузки). Затем download.php будет считывать требуемый файл из своего местоположения и отправлять он в браузер с соответствующими заголовками для принудительной загрузки.

Храните файлы на стороне вашего веб-корня, но затем убедитесь, что папка, в которой они хранятся, находится в директиве open_basedir в файле php.ini, это позволит вам получить к ним доступ из скрипта PHP. Сохранение их вне корневого веб-узла означает, что они никогда не будут напрямую доступны через HTTP.

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

Поместите .htacces в папку со сценарием, который переписывает файл, запрошенный из этой папки, переменной. Это заставляет его выглядеть так, как будто они напрямую обращаются к файлу, а это не так. Лично я бы поместил только один скрипт в эту папку, чтобы все было просто. Так:

http://www.yourdomain.com/files/expensive_song.mp3

на самом деле переписывает:

http://www.yourdomain.com/files/download_file.php?filename=expensive_song.mp3

Удачи.

Если у вас есть доступ к запуску Lighttpd, вам обязательно нужно проверить модуль Mod_SecDownload . Я использовал это в предыдущем проекте, который надежно продавал файлы видео и изображений.

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

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

Сгенерированный URL должен иметь формат:

<uri-prefix> / <token> / <timestamp-in-hex> / <rel-path>, который выглядит как "yourserver.com/bf32df9cdb54894b22e09d0ed87326fc/435cc8cc/secure.tar.gz"

<токен> – это MD5

  1. секретная строка (пользователь поставил)
  2. (начинается с /)
  3. <Метка-в-шестнадцатеричной>

Как вы можете видеть, токен не привязан к пользователю вообще. Единственным ограничивающим фактором является отметка времени, которая используется для аннулирования URL-адреса после заданного таймаута (secdownload.timeout).

У вас может быть URL-адрес авторизационного кода для покупателя. Вы заставляете ее снова войти в систему, проверить, в каком файле находится код, а затем передать файл ей. Вот пример кода PHP из osCommerce (я писал это давно).

// Now send the file with header() magic header("Expires: Mon, 26 Nov 1962 00:00:00 GMT"); header("Last-Modified: " . gmdate("D,d MYH:i:s") . " GMT"); header("Cache-Control: no-cache, must-revalidate"); header("Pragma: no-cache"); header("Content-Type: Application/octet-stream"); header("Content-disposition: attachment; filename=" . $downloads['orders_products_filename']); if (DOWNLOAD_BY_REDIRECT == 'true') { // This will work only on Unix/Linux hosts tep_unlink_temp_dir(DIR_FS_DOWNLOAD_PUBLIC); $tempdir = tep_random_name(); umask(0000); mkdir(DIR_FS_DOWNLOAD_PUBLIC . $tempdir, 0777); symlink(DIR_FS_DOWNLOAD . $downloads['orders_products_filename'], DIR_FS_DOWNLOAD_PUBLIC . $tempdir . '/' . $downloads['orders_products_filename']); if (file_exists(DIR_FS_DOWNLOAD_PUBLIC . $tempdir . '/' . $downloads['orders_products_filename'])) { tep_redirect(tep_href_link(DIR_WS_DOWNLOAD_PUBLIC . $tempdir . '/' . $downloads['orders_products_filename'])); } } 

Вот пример кода того, что я сделал для чего-то очень похожего:

 // $mimeType is the mime type of the file header('Content-type: ' . $mimeType); // this will get the size of the file // (helps for giving the size to the browser so a percent complete can be shown) header('Content-length: ' . (string) (filesize($path))); // disposition is either attachment (for binary files that can't be read by the browser) // or inline (for files that can be read by the browser // some times you have play with this to get working so users get the download window in all browsers // original filename is the name you want to users to see // (shouldn't have any special characters as you can end up with weird issues) header('Content-Disposition: ' . $disposition . '; filename=' . $originalFilename); // the next 2 lines try to help the browser understand that the file can't be cached // and should be downloaded (not viewed) header('Pragma: Public'); header('Cache-control: private'); // this will output the file to browser readfile($path); 

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

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

Некоторые веб-серверы, такие как Lighty и Nginx, реализуют заголовок X-Sendfile. Допустим, у вас есть приложение Django, у вас есть возможность вернуть заголовок X-Sendfile, который указывает на файл, который вы хотите отправить. Затем lighttpd будет обслуживать этот файл.

Файл может находиться в недоступном для Интернета месте (это не переадресация 301), и поскольку ваше приложение обслуживает заголовок, вы можете сделать авторизацию в первую очередь.

Это намного лучше, чем обслуживание статических файлов из вашего приложения. Веб-сервер оптимизирован для статических файлов, и он будет быстрее и намного легче на ресурсах. Если вы обрабатываете несколько запросов, вам следует использовать X-Sendfile.

Об этом неплохом сообщении в блоге:

http://blog.zacharyvoase.com/2009/09/08/sendfile/

Инструкции Lighttpd / PHP можно найти здесь:

http://redmine.lighttpd.net/wiki/1/X-LIGHTTPD-send-file

Инструкции NGINX можно найти здесь:

http://wiki.nginx.org/XSendfile

Также существует ранний выпуск Apache mod, который делает то же самое:

https://tn123.org/mod_xsendfile/

Многие загружаемые URL-адреса, которые я видел, которые основаны на покупке, как правило, используют некоторую директиву и другую динамическую информацию в качестве части URL-адреса, чтобы сделать ее не такой простой, как угадывание одного идентификатора. В итоге вы можете использовать guid / datetimepurchased / id или что-то подобное в качестве части пути.

Дополнительным вариантом будет обеспечение того, чтобы пользователь вошел в систему, прежде чем разрешить загрузку, чтобы обеспечить дополнительный уровень безопасности.

Ну, во-первых, вы определенно не хотите напрямую ссылаться на файл. Вероятно, вы захотите отправить пользователю ссылку на созданный вами сервис (или даже на страницу) с сгенерированным аргументом id, который приведет к загрузке файла, если будут выполнены определенные критерии.

Эти критерии сложны, так как вам нужно разрешить пользователю загружать файл более одного раза (в случае, если он не сможет загрузить полный файл в первый раз или удалит его случайно и т. Д.), Но как только ссылка работает, он работает, пока вы не убьете его.

Я бы предложил использовать время или IP для фильтрации запросов на загрузку.

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

IP: Когда кто-то купит файл у вас, сообщите им, что они смогут загружать файл только с этого IP-адреса. Служба загрузки может, конечно, проверить это при попытке загрузить файл.

Кажется, что оба они легко доступны одновременно.

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