五個常見的 Nginx 配置錯誤
譯者 | 王強
策劃 | 萬佳
Nginx 是最常見的 Web 服務器。本文介紹五個常見的配置錯誤,它們會降低網站的安全性。
本文主要關注以下常見的 Nginx 錯誤配置:
-
根目錄位置丟失
-
off-by-slash
-
不安全的變量使用
-
原始後端響應讀取
-
merge_slashes
設置爲 off
1 根目錄位置丟失
1server {
2 root /etc/nginx;
3 location /hello.txt {
4 try_files $uri $uri/ =404;
5 proxy_pass http://127.0.0.1:8080/;
6 }
7}
8
在我們收集的近 50000 個 Nginx 配置文件中,最常見的根路徑如下:
經常配置錯誤的 Nginx 根路徑
2off-by-slash
1server {
2 listen 80 default_server;
3 server_name _;
4 location /static {
5 alias /usr/share/nginx/static/;
6 }
7 location /api {
8 proxy_pass http://apiserver/v1/;
9 }
10}
11
這個配置錯誤指的是由於缺少一個斜槓,所以有可能沿路徑上移一步。OrangeTsai 在 Blackhat 演講 “Breaking Parser Logic!” 中讓這項技術廣爲人知。
https://i.blackhat.com/us-18/Wed-August-8/us-18-Orange-Tsai-Breaking-Parser-Logic-Take-Your-Path-Normalization-Off-And-Pop-0days-Out-2.pdf
在這個演講中,他展示瞭如何結合一條缺少尾斜槓的location
指令與一條alias
指令,來讀取 Web 應用程序的源代碼。鮮爲人知的是,它還可以與其他指令(例如proxy_pass
)一起使用。我們來分解一下究竟發生了什麼事情,以及爲什麼它能起作用。
1location /api {
2 proxy_pass http://apiserver/v1/;
3 }
4
如果一個 Nginx 服務器運行能在 server 訪問的以下配置,則可以假定訪問者只能訪問http://apiserver/v1/
下的路徑。
1http://server/api/user -> http://apiserver/v1//user
2
當請求http://server/api/user
時,Nginx 將首先規範化 URL。然後,它會查看前綴 /api
是否與 URL 匹配,本例中是匹配的。
然後,服務器從 URL 中刪除該前綴,保留/user
路徑。再將此路徑添加到proxy_pass
URL 中,從而得到最終 URL http://apiserver/v1//user
。
請注意,這個 URL 中存在雙斜槓,因爲 location 指令不以單斜槓結尾,並且proxy_pass
URL 路徑以單斜槓結尾。大多數 Web 服務器會將http://apiserver/v1//user
標準化爲http://apiserver/v1/user
,這意味着即使配置錯誤,所有內容仍將按預期運行,並且可能不會引起注意。請求http://server/api../
可以利用這種錯誤配置,這將導致 Nginx 請求 URL http://apiserver/v1/../
,其標準化爲http://apiserver/
。這可能產生的影響取決於利用這種錯誤配置可以達到的效果。例如,這可能導致 Apache 服務器狀態通過 URL http://server/api../server-status
公開,或者可能讓不希望公開訪問的路徑可訪問。
Nginx 服務器配置錯誤的一個跡象是,當 URL 中的一個斜槓被刪除時,服務器仍會返回相同的響應。例如,如果http://server/api/user
和http://server/apiuser
返回相同的響應,則服務器可能容易受到攻擊。這將導致發送以下請求:
1http://server/api/user -> http://apiserver/v1//user
2http://server/apiuser -> http://apiserver/v1/user
3
3 不安全的變量使用
一些框架、腳本和 Nginx 配置會不安全地使用 Nginx 存儲的變量。這可能會導致諸如 XSS、繞過 HttpOnly 保護、信息泄露,甚至在某些情況下的 RCE 之類的問題。
SCRIPT_NAME
像下面這樣的配置:
1location ~ \.php$ {
2 include fastcgi_params;
3 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
4 fastcgi_pass 127.0.0.1:9000;
5 }
6
主要問題是 Nginx 會將所有 URL 發送到以.php
結尾的 PHP 解釋器,即使該文件在磁盤上不存在。這是 Nginx 創建的 “陷阱和常見錯誤” 文檔中提到的,在許多 Nginx 配置中都常見的錯誤。
https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#passing-uncontrolled-requests-to-php?fileGuid=xVX6hcx8WXCYPVGd
如果這個 PHP 腳本試圖基於SCRIPT_NAME
定義一個基本 URL,則將發生 XSS。
1<?php
2if(basename($_SERVER['SCRIPT_NAME']) ==
3basename($_SERVER['SCRIPT_FILENAME']))
4 echo dirname($_SERVER['SCRIPT_NAME']);
5?>
6GET /index.php/<script>alert(1)</script>/index.php
7SCRIPT_NAME = /index.php/<script>alert(1)</script>/index.php
8
使用 $uri 可導致 CRLF 注入
與 Nginx 變量有關的另一個錯誤配置是使用$uri
或$document_uri
代替$request_uri
。$uri
和$document_uri
包含標準化的 URI,而 Nginx 中的normalization
包括對 URI 解碼的 URL。Volema 發現,在 Nginx 配置中創建重定向時經常會使用$uri
,結果導致 CRLF 注入。
一個易受攻擊的 Nginx 配置的示例如下:
1location / {
2return 302 https://example.com$uri;
3}
4
HTTP 請求的換行符爲 \ r(回車)和 \ n(換行)。對換行符進行 URL 編碼將導致以下字符表示形式%0d%0a
。如果將這些字符包含在對配置錯誤的服務器的一個請求中(例如http://localhost/%0d%0aDetectify:%20clrf
),則該服務器將使用一個名爲Detectify
的新標頭進行響應,因爲 $uri 變量包含 URL 解碼的換行符。
1HTTP/1.1 302 Moved Temporarily
2Server: nginx/1.19.3
3Content-Type: text/html
4Content-Length: 145
5Connection: keep-alive
6Location: https://example.com/
7Detectify: clrf
8
Any 變量
在某些情況下,用戶提供的數據可以視爲 Nginx 變量。目前尚不清楚爲什麼會發生這種情況,但如這份 H1 報告所示,這種情況並不罕見或不容易測試。如果搜索錯誤消息,我們可以看到它是在 SSI 過濾器模塊中找到的,表明這是由 SSI 引起的。
https://hackerone.com/reports/370094?fileGuid=xVX6hcx8WXCYPVGd
一種測試方法是設置一個引用標頭值:
1$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’
2
我們掃描了這種錯誤配置,發現了幾個實例,用戶可以在其中打印 Nginx 變量的值。我們發現易受攻擊實例的數量有所下降,這可能表明這個漏洞已經做了修補。
4 原始後端響應讀取
使用 Nginx 的proxy_pass
,可以攔截後端創建的錯誤和 HTTP 標頭。如果你要隱藏內部錯誤消息和標頭以便 Nginx 處理,這個方法會非常有用。如果後端回答一個錯誤,Nginx 將自動提供一個自定義錯誤頁面。但如果 Nginx 無法理解這是一個 HTTP 響應怎麼辦?
如果一個客戶端向 Nginx 發送了一個無效的 HTTP 請求,則該請求將按原樣轉發到後端,後端將使用其原始內容來應答。然後,Nginx 將無法理解無效的 HTTP 響應,而將其轉發給客戶端。想象一個這樣的 uWSGI 應用程序:
1def application(environ, start_response):
2 start_response('500 Error', [('Content-Type',
3'text/html'),('Secret-Header','secret-info')])
4 return [b"Secret info, should not be visible!"]
5
並在 Nginx 中使用以下指令:
1http {
2 error_page 500 /html/error.html;
3 proxy_intercept_errors on;
4 proxy_hide_header Secret-Header;
5}
6
如果後端的響應狀態大於 300,proxy_intercept_errors 將提供一個自定義響應。在上面的 uWSGI 應用程序中,我們將發送一個500 Error
,Nginx 將攔截該錯誤。
proxy_hide_header 可以自解釋;它將從客戶端隱藏任何指定的 HTTP 標頭。
如果我們發送一個普通的 GET 請求,則 Nginx 將返回:
1HTTP/1.1 500 Internal Server Error
2Server: nginx/1.10.3
3Content-Type: text/html
4Content-Length: 34
5Connection: close
6
但是,如果我們發送一個無效的 HTTP 請求,例如:
1GET /? XTTP/1.1
2Host: 127.0.0.1
3Connection: close
4
我們將收到以下答覆:
1XTTP/1.1 500 Error
2Content-Type: text/html
3Secret-Header: secret-info
4Secret info, should not be visible!
5
5merge_slashes 設置爲 off
默認情況下,merge_slashes 指令設置爲 “on”,這是一種將兩個或多個正斜槓壓縮爲一個的機制,因此///
將變爲/
。如果 Nginx 用作反向代理,並且被代理的應用程序容易受到本地文件包含內容的影響,則在請求中使用額外的斜槓可能會留出惡意利用空間。
http://nginx.org/en/docs/http/ngx_http_core_module.html#merge_slashes?fileGuid=xVX6hcx8WXCYPVGd
我們發現 33 個 Nginx 配置文件的merge_slashes
設置爲 “off”。
6 自己嘗試一下
我們創建了一個 GitHub 存儲庫,你可以在其中使用 Docker 來設置你自己的易受攻擊的 Nginx 測試服務器,以及本文中討論的一些錯誤配置,然後嘗試自己找到它們。
https://github.com/detectify/vulnerable-nginx?fileGuid=xVX6hcx8WXCYPVGd
7 總結
Nginx 是一個非常強大的 Web 服務器平臺,很好理解爲什麼它會被廣泛使用。但是,靈活的配置意味着你更容易犯錯誤,而這些錯誤可能會對安全性產生影響。請不要使用這些常見的錯誤配置,以免攻擊者輕易地入侵你的網站。
原文鏈接:
https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/?fileGuid=xVX6hcx8WXCYPVGd
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/hXZJCthua5VwBftP_hO6pA