Nginx常見的錯誤配置


Blog:博客園 個人

翻譯自Common Nginx misconfigurations that leave your web server open to attack

Nginx是當前主流的Web服務。 以下是一些最常見的錯誤配置。

Missing root location

server {
        root /etc/nginx;

        location /hello.txt {
                try_files $uri $uri/ =404;
                proxy_pass http://127.0.0.1:8080/;
        }
}

root指令指定了Nginx的根目錄。 在上面的示例中,根目錄是/etc/nginx,這意味着我們可以訪問該目錄下的文件。 上面的配置沒有/locationlocation / {...}),只有/hello.txtlocation。 因此,將對root指令進行全局設置,這意味着對/的請求會將您帶到本地路徑/etc/nginx

GET /nginx.conf這樣簡單的請求將顯示存儲在/etc/nginx/nginx.conf中的Nginx配置文件的內容。 如果將根設置為/etc,則對/nginx/nginx.conf的GET請求將顯示配置文件。 在某些情況下,可能會訪問其他配置文件、訪問日志甚至HTTP基本身份驗證的加密憑據。

在我們收集的近50,000個Nginx配置文件中,最常見的根路徑如下:

frequently misconfigured nginx root paths

Off-By-Slash

server {
        listen 80 default_server;

        server_name _;

        location /static {
                alias /usr/share/nginx/static/;
        }

        location /api {
                proxy_pass http://apiserver/v1/;
        }
}

由於Off-by-slash配置錯誤,缺少/,導致有可能沿路徑上移一步。 Orange Tsai在Blackhat的演講“ Breaking Parser Logic!”中使這項技術廣為人知。 在本次演講中,他展示了location指令與alias指令結合使用的缺失斜杠如何使讀取Web應用程序的源代碼成為可能。 鮮為人知的是,它還可以與其他指令(例如proxy_pass)一起使用。 讓我們來分解一下正在發生的事情以及它為什么起作用。

        location /api {
                proxy_pass http://apiserver/v1/;
        }

如果Nginx服務器可以訪問以下配置,則可以假定只能訪問http://apiserver/v1/下的路徑。

http://server/api/user -> http://apiserver/v1//user

當請求http://server/api/user時,Nginx將首先規范化URL。 然后,它會查看前綴/api是否與URL匹配,在這種情況下,上述示例中是與URL匹配的。 然后,從URL中刪除該前綴,因此保留/user路徑。 然后將此路徑添加到proxy_pass URL中,從而得到最終URL http://apiserver/v1//user。 請注意,URL中存在雙斜杠,因為location指令不以斜杠結尾,並且proxy_pass URL路徑以斜杠結尾。 大多數Web服務器會將http://apiserver/v1//user 的user標准化為http://apiserver/v1/user,這意味着即使配置錯誤,所有內容仍將按預期運行,並且可能不會引起注意。

通過請求http://server/api../可以利用這種錯誤配置,這將導致Nginx請求標准化為http://apiserver/v1/../的URL http://apiserver/。 這可能產生的影響取決於利用這種錯誤配置可以達到的效果。 例如,這可能導致Apache服務器狀態通過URL http://server/api../server-status 公開,或者可能使不希望公開訪問的路徑可訪問。

Nginx服務器配置錯誤的一個跡象是,當URL中的斜杠被刪除時,服務器仍會返回相同的響應。 例如,如果http://server/api/userhttp://server/apiuser返回相同的響應,則服務器可能容易受到攻擊。 這將導致發送以下請求:

http://server/api/user -> http://apiserver/v1//user
http://server/apiuser -> http://apiserver/v1/user

Unsafe variable use

一些框架、腳本和Nginx配置不安全地使用Nginx存儲的變量。 這可能會導致諸如XSS,繞過HttpOnly保護、信息泄露,在某些情況下甚至是RCE。

SCRIPT_NAME

如下配置:

        location ~ \.php$ {
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_pass 127.0.0.1:9000;
        }

主要問題是Nginx會將所有URL發送到以.php結尾的PHP解釋器,即使該文件在磁盤上不存在。 這是Nginx創建的Pitfalls and Common Mistakes文檔中羅列的許多Nginx錯誤配置中的一種。

如果PHP腳本試圖基於SCRIPT_NAME定義基本URL,則將發生XSS。

<?php

if(basename($_SERVER['SCRIPT_NAME']) ==
basename($_SERVER['SCRIPT_FILENAME']))
   echo dirname($_SERVER['SCRIPT_NAME']);

?>

GET /index.php/<script>alert(1)</script>/index.php
SCRIPT_NAME  =  /index.php/<script>alert(1)</script>/index.php

Usage of $uri can lead to CRLF Injection

與Nginx變量有關的另一個錯誤配置是使用$uri$document_uri而不是$request_uri$uri$document_uri包含標准化的URI,而Nginx中的標准化包括對URI進行解碼的URL。 Volema 發現,在Nginx配置中創建重定向會導致CRLF注入時,通常使用$uri

易受攻擊的Nginx配置的示例如下:

location / {
  return 302 https://example.com$uri;
}

HTTP請求的新行字符為\r(回車)和\n(換行)。 對新行字符進行URL編碼將導致以下字符%0d%0a的表示形式。 如果這些字符包含在對服務器的配置錯誤的請求(例如http://localhost/%0d%0aDetectify:%20clrf)中,則該服務器將使用名為Detectify的新標頭進行響應,這是因為$uri變量包含URL解碼后的換行字符。

HTTP/1.1 302 Moved Temporarily
Server: nginx/1.19.3
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: https://example.com/
Detectify: clrf

通過https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/了解有關CRLF注射和反應分裂的風險的更多信息。

Any variable

在某些情況下,用戶提供的數據可以視為Nginx變量。 目前尚不清楚為什么會發生這種情況,但如本H1報告所示,這種情況並不罕見或不容易測試。 如果搜索錯誤消息,我們可以看到它在 SSI filter module中找到,從而表明這是由於SSI引起的。

測試方法如下:

$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’

Raw backend response reading

使用Nginx的proxy_pass,可以攔截后端創建的錯誤和HTTP標頭。 如果要隱藏內部錯誤消息和標頭,以便由Nginx處理,則這非常有用。 如果后端響應一個請求,Nginx將自動提供一個自定義錯誤頁面。 但是,如果Nginx無法理解這是HTTP響應怎么辦?

如果客戶端向Nginx發送無效的HTTP請求,則該請求將按原樣轉發到后端,后端將使用其原始內容進行應答。 然后,Nginx將無法理解無效的HTTP響應,而會將其轉發給客戶端。 想象一下這樣的uWSGI應用程序:

def application(environ, start_response):
   start_response('500 Error', [('Content-Type',
'text/html'),('Secret-Header','secret-info')])
   return [b"Secret info, should not be visible!"]

Nginx配置如下:

http {
   error_page 500 /html/error.html;
   proxy_intercept_errors on;
   proxy_hide_header Secret-Header;
}

如果后端的響應狀態大於300, proxy_intercept_errors將提供自定義響應。在上面的uWSGI應用程序中,我們將發送500錯誤,Nginx將攔截該錯誤。

proxy_hide_header:可以隱藏任何指定的來自客戶端的HTTP標頭。

如果我們發送普通的GET請求,則Nginx將返回:

HTTP/1.1 500 Internal Server Error
Server: nginx/1.10.3
Content-Type: text/html
Content-Length: 34
Connection: close

但是,如果我們發送無效的HTTP請求,例如:

GET /? XTTP/1.1
Host: 127.0.0.1
Connection: close

我們將收到以下響應:

XTTP/1.1 500 Error
Content-Type: text/html
Secret-Header: secret-info

Secret info, should not be visible!

merge_slashes set to off

默認情況下,merge_slashes指令設置為on,這是一種將兩個或多個正斜杠壓縮為一個的機制,因此///將變為/。 如果Nginx用作反向代理,並且被代理的應用程序容易受到本地文件包含的影響,則在請求中使用額外的斜杠可能會留出利用空間。 Danny Robinson and Rotem Bar對此進行了詳細描述。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM