Nginx

僅取決於目錄名稱的安全連結?

  • July 27, 2017

我目前正在努力使 nginx 僅保護文件夾名稱,而與其中的文件名無關。假設我正在訪問文件夾 /one/two/three 中的文件,它看起來像這樣:

http://example.com/one/two/35d6d33467aae9a2e3dccb4b6b027878/file.mp3

因此文件夾“三”只能由目錄 md5 訪問,而實際路徑將返回 403。我有數千個這樣的文件夾,所以我需要將它們隱藏起來,但可以通過只知道 md5 的遠端客戶端對它們進行靜態訪問執行。

同時,這樣的連結也應該起作用:

http://example.com/one/two/35d6d33467aae9a2e3dccb4b6b027878/four/file.mp3

所以只有一個特定的目錄級別是隱藏的。

您可以通過使用您想要保護的隱藏文件夾或文件的內部位置以及檢查您的散列程式碼是否允許訪問您的文件的方法來實現這一點。

Nginx 不允許直接訪問您的隱藏文件(例如 /protected/folder1/folder2/file.pdf),因為該位置已被標記為內部。但是您的腳本可以使用特殊標頭X-Accel-Redirect 重定向到此位置。

因此,您可以讓 Nginx 做它最擅長的事情,傳遞數據,並且您的腳本僅檢查是否允許訪問。

下面你可以看到一個簡單的例子。

文件夾 /data 包含公共內容(例如公共圖像)。非公開圖像儲存在不同的文件夾(在 htdocs 之外)並通過位置 /protected_data 提供。此位置具有包含受保護圖像的文件夾的別名和內部指令。所以這是無法從外部訪問的。

在 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);
}

引用自:https://serverfault.com/questions/818703