В настоящее время я изо всех сил пытаюсь сделать nginx безопасным только для имени папки, независимо от имени файла внутри нее. Скажем, я обращаюсь к файлу в папке / one / two / three, это будет выглядеть так:
http://example.com/one/two/35d6d33467aae9a2e3dccb4b6b027878/file.mp3
Таким образом, к папке «три» будет доступ только из каталога md5, а реальный путь вернет 403. У меня есть тысячи таких папок, поэтому мне нужно держать их скрытыми, но иметь статический доступ к ним через удаленных клиентов, которые знают только md5 в время выполнения.
Между тем, такие ссылки тоже должны работать:
http://example.com/one/two/35d6d33467aae9a2e3dccb4b6b027878/four/file.mp3
Таким образом, скрыт только определенный уровень каталога.
Вы можете добиться этого, используя внутренние местоположения для скрытых папок или файлов, которые вы хотите защитить, и способ проверить, разрешает ли ваш хешированный код доступ к вашим файлам или нет.
Прямой доступ к вашим скрытым файлам (например, /protected/folder1/folder2/file.pdf) не разрешен Nginx, поскольку это местоположение было помечено как внутреннее. Но ваш скрипт может перенаправить в это место со специальным заголовком X-Accel-Redirect.
Таким образом, вы можете позволить Nginx делать то, что он умеет лучше всего, доставлять данные, а ваш скрипт проверяет, только если доступ разрешен или нет.
Ниже вы можете увидеть простой пример этого.
Папка / данные содержат общедоступный контент (например, общедоступные изображения). Непубличные изображения хранились в другой папке (вне htdocs) и предоставлялись через location / protected_data. Это место имеет псевдоним для папки, содержащей защищенные изображения, и директиву internal. Так что это недоступно извне.
В сценарии PHP я сначала проверил, существует ли защищенный файл. Это может быть проблемой безопасности, но обычно проверка прав пользователя обходится дороже (отнимает много времени), чем простой file_exists. Поэтому, если безопасность важнее производительности, вы можете изменить порядок проверок.
Конфигурация сервера Nginx:
...
root /var/www/test/htdocs;
location / {
index index.php index.htm index.html;
}
location /data {
expires 30d;
try_files $uri /grant-access.php;
}
location /protected_data {
expires off;
internal;
alias /var/www/test/protected_data;
}
location ~ \.php$ {
if (!-e $request_filename) {
rewrite / /index.php last;
}
expires off;
include fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_read_timeout 300;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
access_log /var/log/nginx/access.log combined;
}
...
Скрипт PHP:
<?php
// this is the folder where protected files are stored (see Nginx config alias directive of the internal location)
define('PROTECTED_FOLDER_FILESYSTEM', '/var/www/test/protected_data');
// this is the url path we have to replace (see Nginx config with the try_files directive)
define('PROTECTED_PUBLIC_URL', '/data');
// this is the url path replacement (see Nginx config with the internal directive)
define('PROTECTED_INTERNAL_URL', '/protected_data');
// check if file exists
$filename = str_replace(
PROTECTED_PUBLIC_URL .'/',
'/',
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
);
if (!file_exists(PROTECTED_FOLDER_FILESYSTEM . $filename)) {
http_response_code(404);
exit;
}
// check if access is allowed (here we will use a random check)
if (rand(1,2)==1) {
// grant access
header('X-Accel-Redirect: ' . PROTECTED_INTERNAL_URL . $filename);
} else {
// deny access
http_response_code(403);
}
Чтобы это стало возможным, nginx должен иметь возможность определять, что хэш 35d6d33467aae9a2e3dccb4b6b027878
соответствует three
. На сегодняшний день Nginx не может этого сделать (и я не думаю, что это входит в список задач).
Единственный способ, которым я мог представить, как ты мог чего-то добиться аналогичный будет размещать файлы в другом месте и создавать символические ссылки с хешем целевого каталога в качестве имени ссылки в корневом каталоге вашего местоположения в момент создания / загрузки файлов.
Например, местоположение вашего веб-сервера http://example.com/one/two/
указывает на каталог (скажем /var/www/html/
), где символическая ссылка 35d6d33467aae9a2e3dccb4b6b027878
указывает на каталог three/
который находится в другом месте (например, /var/www/protected/
).
При загрузке потребуется запустить скрипт или что-то подобное, чтобы создать папку. three/
в /var/www/protected/
, хеш "три", а затем создать символическую ссылку /var/www/html/35d6d33467aae9a2e3dccb4b6b027878
.
Это единственный способ, который я мог придумать.