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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
4
0
6 319
8

Ответы 8

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

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

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

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

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

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

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

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

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

По сути, вы не даете пользователям прямой URL-адрес файла. Разрешения на основе сервера здесь не при чем.

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

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

Вы можете сделать так, чтобы 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 M Y H: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']));
    }
  }

OMG - теп_ это что зло osCommerce? ;)

Till 17.10.2008 04:33

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

As the webserver doesn't know anything about the permissions used in the app, the resulting URL would be available to every user who knows the URL.

mod_secdownload removes this problem by introducing a way to authenticate a URL for a specified time. The application has to generate a token and a timestamp which are checked by the webserver before it allows the file to be downloaded by the webserver.

The generated URL has to have the format:

<uri-prefix>/<token>/<timestamp-in-hex>/<rel-path> which looks like "yourserver.com/bf32df9cdb54894b22e09d0ed87326fc/435cc8cc/secure.tar.gz"

<token> is an MD5 of

  1. a secret string (user supplied)
  2. (starts with /)
  3. <timestamp-in-hex>

As you can see, the token is not bound to the user at all. The only limiting factor is the timestamp which is used to invalidate the URL after a given timeout (secdownload.timeout).

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

// $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);

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

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

Храните файлы вне корневого веб-сайта, но затем убедитесь, что папка, в которой вы их храните, находится в директиве 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

Удачи.

Некоторые веб-серверы, такие как 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, который делает то же самое:

https://tn123.org/mod_xsendfile/

Другие вопросы по теме