Website development
August 2008 21

Использование Nginx и php для проверки прав доступа перед отдачей файлов

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

  1. Раздавать файлы с помощью скрипта на php(заменить php на то, что нравится больше). При данном подходе мы передаем в качестве параметра скрипту имя файла. Код проверяет все условия, при которых возможно получения доступа к данному файлу и принимает решение, выдать 404 или запрошенный файл. Данный подход подходит для мелких файлов, однако при возрастании размера отдаваемого файла он будет потреблять много системных ресурсов, т.к. файл будет вычитываться в память и затем отдаваться.
  2. Использовать некоторые неочевидные возможности веб-серверов.


Рассмотрим второй вариант.
Так исторически сложилось, что для обратного проксирования я стал использовать nginx. Покопавшись в его документации я обнаружил что с помощью данного сервера можно контролировать раздачу файлов, проверяя права доступа непосредственно перед отдачей контента.
Итак, приступим.
За nginx у меня стоит апач, который обрабатывает запросы на динамический контент, описано примерно так:
location / {
proxy_pass 127.0.0.1/;
}


Сначала складываем наш контент в выделенные директории. В моем случае сайт расположен в /var/www, защищенный контент я выложил в /var/www/protected. Для данной секции я добавил в конфигурации nginx следующие строки:
location /protected {
root /var/www;
internal;
}


Здесь root указывает, где находится сайт. Директива internal указывает что данная область будет доступна только если происходит внутреннее перенаправление nginx в директорию protected. Таким образом, даже зная прямой адрес ресурса на сервере, мы будем получать 404 в ответ на наш запрос.
Первый этап завершен, контент не доступен по прямой ссылке.
Однако нам нужно при некоторых условиях данный контент все же показывать. Для этого мы приводим первый location к следующему виду:
location / {
rewrite ^/download/(.*) /download.php?path=$1 last;

proxy_pass 127.0.0.1/;
}

Таким образом, все запросы, которые пытаются забрать что-то из download, будут перенаправляться на файл download.php. В данном файле будет приниматься решение о разрешении/запрещении доступа пользователю к файлу. Сам исходный текст файла download.php может быть таким:
<?
$path = $_GET[«path»];
//некоторые действия по проверке прав доступа
header(«X-Accel-Redirect: /protected/». $path);
?>

Если пользователю разрешен доступ к данному файлу, тогда отправляем данный заголовок, в ином случае отправляем ему 404. После определения прав доступа работа php завершена. Далее nginx получает данный заголовок, выполняет внутреннее перенаправление и начинает отдавать пользователю запрошенный файл.

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

Основой для статьи полужил материал: blog.kovyrin.net/2006/11/01/nginx-x-accel-redirect-php-rails/lang/ru
Использовались материалы: sysoev.ru/nginx/docs

P.S. Данная статья не претендует на полноту и не может рассматриваться как инструкция по настройке сервера nginx. В ней сознательно опущены моменты, касательно сжатия, кэширования и тому подобных вещей.
+20
8.9k 88
Comments 12
Similar posts