Nginx 在現代網路基礎架構中扮演著關鍵角色,但其設定不當也可能成為攻擊者的目標。我將深入剖析 Nginx 的安全性議題,並提供強化策略,協助您建構更安全的網路環境。
設定 Nginx 時,root
指令至關重要,它指定伺服器提供檔案的基底目錄。設定不當可能導致嚴重安全風險。
以下是一個錯誤的設定範例:
server {
root /etc/nginx;
location /hello.txt {
try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1:8080/;
}
}
這個設定缺少 location / { ... }
區塊,導致 root
指令(/etc/nginx
)全域套用,影響所有請求,包括根路徑 /
。這可能讓攻擊者存取 /etc/nginx
中的敏感檔案,例如 nginx.conf
。
攻擊情境:利用根目錄位置漏洞
攻擊者可以傳送特定 HTTP 請求來取得敏感檔案:
curl http://example.com/nginx.conf
如果 root
目錄設定更廣泛,例如 /etc
,攻擊者甚至可以存取 /etc/passwd
和 /etc/shadow
等檔案。
防禦策略
- 限制根目錄: 將
root
目錄設定為較不敏感的位置,例如/var/www/html
。 - 定義根目錄位置: 明確定義
location / { ... }
區塊,安全地處理根路徑請求。 - 使用許可權和存取控制: 確保 Nginx worker 程式無法讀取敏感檔案,或透過檔案系統許可權進行保護。
不安全的路徑限制
Nginx 設定檔通常包含根據路徑的限制,以保護敏感目錄或頁面。然而,Nginx 處理 URL 請求的方式可能存在繞過這些限制的漏洞。
潛在的繞過技術
- 尾斜線不比對: Nginx 以不同方式處理帶尾斜線和不帶尾斜線的 URL。攻擊者可能利用此行為繞過限制。例如,如果
/admin
被拒絕,但/admin.
沒有被明確拒絕,則可能被視為不同的路徑。 - URL 編碼: 透過編碼 URL 的部分內容,攻擊者可能繞過簡單的字串比對。例如,
%61dmin
可能被處理為單獨的路徑。 - 大小寫敏感性: 在特定設定中,大小寫敏感性可能被利用。例如,如果 Nginx 設定為不區分大小寫,則
/Admin
可能繞過/admin
的限制。 - 新增 Null 位元組: 在某些伺服器設定中,附加 Null 位元組(
%00
)可能透過提前終止字串處理來繞過限制。
攻擊情境:利用路徑限制繞過
假設有一個限制存取 /admin
頁面的設定:
location = /admin {
deny all;
}
location = /admin/ {
deny all;
}
攻擊者可以嘗試使用 /admin.
、%61dmin
或 /Admin
等變體來繞過限制。
防禦策略
- 明確拒絕所有變體: 使用正規表示式或其他方法明確拒絕所有可能的繞過路徑。
- 正確解碼 URL: 確保伺服器正確解碼 URL,防止編碼字元繞過限制。
- 統一大小寫處理: 根據需求設定大小寫敏感性,並確保一致性。
- 過濾 Null 位元組: 在後端系統中過濾 Null 位元組,防止其被用於繞過限制。
圖表示例:展示路徑繞過攻擊
graph LR Applied[Applied] B[B] Bypass[Bypass] Restriction[Restriction] A[Client Request: /admin.] --> B{Nginx Path Matching} B -- Bypass Restriction --> C[Access Granted] B -- Restriction Applied --> D[Access Denied]
此圖表說明瞭客戶端如何透過請求 /admin.
來繞過 Nginx 的路徑限制,最終獲得存取許可權。
(後續內容將繼續探討其他 Nginx 安全性議題,並提供相應的防禦策略和最佳實務。)
## 解讀 Nginx 設定檔的安全性陷阱與防禦策略
身為一位資深技術工作者,我經常在實際專案中看到因為 Nginx 設定檔的錯誤組態而導致的安全性漏洞。這些錯誤看似微小,卻可能造成嚴重的安全風險。這篇文章將探討 Nginx 設定檔中常見的陷阱,包含路徑繞過、不安全的變數使用、正規表示式漏洞以及後端原始回應洩露等問題,並提供相應的防禦策略和最佳實踐。
### 路徑限制繞過攻擊與防禦
Nginx 的路徑限制功能旨在阻止未授權的存取,但如果設定不當,攻擊者可能會利用各種技巧繞過這些限制。以下是一些常見的攻擊手法:
1. **URL 編碼繞過:** 攻擊者可以使用 URL 編碼,例如 `curl http://example.com/%61dmin`,嘗試存取 `/admin` 目錄。如果伺服器未正確解碼路徑,就可能繞過限制。
2. **大小寫變換繞過:** 攻擊者可能嘗試使用不同的字母大小寫,例如 `curl http://example.com/ADMIN`,如果伺服器未強制區分大小寫,也可能繞過限制。
3. **增加尾隨點繞過:** 攻擊者可以在路徑後增加點,例如 `curl http://example.com/admin.`,試圖欺騙伺服器將路徑解釋為與 `/admin` 不同。
4. **空字元注入繞過:** 攻擊者可能注入空字元,例如 `curl http://example.com/admin%00/`,試圖混淆伺服器。
以下 Nginx 設定示範瞭如何使用正規表示式來防禦這些繞過技巧:
```nginx
location ~* ^/admin(/|$) {
deny all;
}
這個設定確保 /admin
、/admin/
、/Admin
等路徑變體都會被拒絕。此外,確保在套用規則之前,URL 路徑已正規化(已解碼、已轉換為小寫等),並實施嚴格的 URI 處理和過濾。
不安全的變數使用與 HTTP 請求分割
$uri
和 $document_uri
變數會自動解碼 URL 編碼字元,如果直接用於處理使用者輸入,可能導致漏洞。例如,以下設定中,$uri
直接用於重新導向 URL:
location / {
return 302 https://example.com$uri;
}
如果攻擊者傳送包含 %0d%0a
(換行符)的請求,例如 http://localhost/%0d%0aDetectify:%20clrf
,伺服器會將其解碼為 \r\n
,可能導致 HTTP 回應分割攻擊,注入惡意標頭。
安全的做法是使用 $request_uri
,它保留原始請求,包括任何 URL 編碼字元:
location / {
return 302 https://example.com$request_uri;
}
正規表示式漏洞
不謹慎的正規表示式也可能引入漏洞。例如,以下正規表示式未檢查空格:
location ~ /docs/([^/])? { ... $1 ... } # 存在漏洞
更安全的版本應檢查空格:
location ~ /docs/([^/\s])? { ... $1 ... } # 安全,檢查了空格
或者:
location ~ /docs/(.*)? { ... $1 ... } # 安全,比對 /docs/ 後的任何內容
後端原始回應洩露
Nginx 可以攔截後端回應,遮蔽內部錯誤和敏感資訊。但在處理無效 HTTP 請求時,此機制可能失效,導致後端原始回應洩露。
假設 Nginx 前端連線到一個 uWSGI 應用程式,該應用程式在發生錯誤時會傳回包含敏感資訊的 HTTP 500 回應,例如包含敏感資訊的 Secret-Header
自訂標頭。
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_intercept_errors on
指令確保當後端傳回 HTTP 狀態碼大於 300 時,Nginx 提供自訂錯誤頁面 /html/error.html
,而不是後端的回應。然而,在某些情況下,例如後端回應格式不正確,這個機制可能失效,導致敏感資訊洩露。
總結來說,Nginx 設定檔的安全性至關重要。仔細檢查變數使用、正規表示式和錯誤處理設定,並定期進行安全測試,才能有效防禦潛在的攻擊。善用 圖表可以更清晰地展示系統架構和流程,有助於理解和避免這些安全陷阱。
graph LR B[B] Error[Error] Intercept[Intercept] Invalid[Invalid] Leakage[Leakage] Request[Request] Valid[Valid] A[Client Request] --> B{Nginx}; B -- Valid Request --> C[Backend Application]; C --> D[Nginx Response]; D --> A; B -- Invalid Request --> E[Backend Error Response]; E -- Leakage --> A; B -- Intercept Error --> F[Custom Error Page]; F --> A;
上圖展示了 Nginx 如何處理請求和錯誤,以及潛在的洩漏路徑。透過理解這些流程,我們可以更好地組態 Nginx,提升網站的安全性。
Nginx 安全設定的陷阱與最佳實務
身為一位資深系統架構師,我經常使用 Nginx 作為網頁伺服器和反向代理。在建置高可靠度和安全性的網路架構時,Nginx 的彈性和效能表現都相當出色。然而,Nginx 設定的複雜性也可能導致一些容易被忽略的安全漏洞。以下我將分享一些我在實務中遇到的 Nginx 安全設定陷阱,並提供一些避免這些問題的最佳實務。
1. merge_slashes 指令的風險
Nginx 的 merge_slashes
指令預設為開啟,它會將 URL 中多個連續的斜線壓縮成一個。雖然這有助於簡化 URL 處理,但也可能隱藏一些漏洞,例如本地檔案包含(LFI)或路徑遍歷攻擊,尤其當 Nginx 作為反向代理時。
http://example.com//etc/passwd // merge_slashes 開啟時會被壓縮成 http://example.com/etc/passwd
如果後端應用程式存在 LFI 漏洞,攻擊者可以利用這個行為繞過安全機制。
解決方案: 在 Nginx 設定中關閉 merge_slashes
指令:
http {
merge_slashes off;
}
2. 惡意回應標頭的防範
某些 HTTP 回應標頭可能改變 Nginx 的行為,例如 X-Accel-Redirect
、X-Accel-Buffering
、X-Accel-Charset
等。如果後端伺服器傳送惡意標頭,可能導致安全風險。
例如,後端伺服器傳送以下標頭:
X-Accel-Redirect: /.env
如果 Nginx 的 root
設定為 /
,這個標頭可能導致 Nginx 內部重新導向到 .env
檔案,洩露敏感的環境變數。
解決方案: 確保後端伺服器不傳送 X-Accel-Redirect
等敏感標頭,除非明確需要。仔細檢查 Nginx 設定,防止意外的存取。
3. map 指令預設值的設定
map
指令常用於將一個值對映到另一個值,例如控制存取或其他邏輯。但如果未指定預設值,可能導致非預期的行為。
http {
map $uri $mappocallow {
/map-poc/public 1;
/map-poc/private 0;
}
}
server {
location /map-poc {
if ($mappocallow = 0) { return 403; }
return 200 "Hello. It is a private area: $mappocallow";
}
}
如果存取 /map-poc/undefined
,$mappocallow
將未設定,可能繞過安全檢查。
解決方案: 務必在 map
指令中指定預設值:
http {
map $uri $mappocallow {
default 0;
/map-poc/public 1;
/map-poc/private 0;
}
}
4. DNS 欺騙漏洞的防護
如果 Nginx 使用外部 DNS 伺服器,存在 DNS 欺騙的風險。
解決方案: 設定 Nginx 使用可信的內部 DNS 伺服器(例如 127.0.0.1):
resolver 127.0.0.1;
此外,確保使用 DNSSEC 驗證 DNS 回應。
5. proxy_pass 和 internal 指令的正確使用
proxy_pass
指令用於將請求轉發到另一個伺服器,而 internal
指令確保某些位置只能在 Nginx 內部存取。如果 internal
指令設定不當,可能允許外部存取敏感的內部位置。
解決方案: 確保內部位置設定正確,與無法從外部存取:
location /internal/ {
internal;
proxy_pass http://backend/internal/;
}
location /public/ {
proxy_pass http://backend/public/;
}
6. proxy_set_header 與 HTTP/2 清文走私攻擊
proxy_set_header
指令可以自訂傳送到代理伺服器的標頭。設定 Upgrade
和 Connection
等標頭時,如果設定不當,可能導致 h2c (HTTP/2 cleartext) 走私攻擊,讓攻擊者繞過 Nginx 的安全檢查,直接與後端伺服器建立連線。
解決方案: 避免直接設定 Upgrade
和 Connection
標頭,讓 Nginx 自動處理。如果需要自訂,務必謹慎設定,並參考官方檔案。
7. 監控與日誌記錄
監控和記錄 Nginx 的請求和回應,特別是錯誤和異常情況,有助於及早發現和應對潛在的攻擊。
Nginx 提供了強大的功能和彈性,但正確的設定至關重要。透過遵循以上最佳實務,可以有效降低安全風險,確保網路架構的安全性。在設定 Nginx 時,務必仔細檢查每個指令的含義和潛在影響,並進行充分的測試和驗證。
graph LR B[B] A[Client] --> B{Nginx} B --> C[Backend Server] D[Attacker] --> B
上圖展示了客戶端、Nginx 和後端伺服器的基本架構,以及攻擊者可能的攻擊路徑。理解這個架構有助於更好地理解 Nginx 的安全設定。
Nginx 設定錯誤:避免升級標頭與連線標頭的誤用
在設定 Nginx 作為反向代理伺服器時,proxy_set_header Upgrade
和 proxy_set_header Connection
指令的使用需要格外謹慎。這些指令允許將客戶端的請求標頭轉發到後端伺服器,但若設定不當,可能導致 HTTP/2 清理文字模式 (h2c) 的升級挾帶攻擊,使攻擊者繞過 Nginx 的安全規則,存取受保護的資源。
漏洞成因分析
問題的核心在於後端伺服器若支援 h2c,攻擊者可以透過偽造的 HTTP/1.1 請求,挾帶 HTTP/2 的設定資訊,誘使後端伺服器將連線升級為 HTTP/2。由於 Nginx 的 proxy_pass
指令僅指定後端伺服器的位址,而非特定路徑,因此升級後的 HTTP/2 連線可以直接與後端伺服器通訊,繞過 Nginx 的路徑限制。
以下列有問題的 Nginx 設定為例:
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/privkey.pem;
location / {
proxy_pass http://backend:9999;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # 存在風險
proxy_set_header Connection $http_connection; # 存在風險
}
location /flag {
deny all;
}
}
此設定中,/flag
路徑被明確禁止存取。然而,由於 Upgrade
和 Connection
標頭被轉發,攻擊者可以利用 h2c 漏洞,直接向後端伺服器的 /flag
路徑傳送請求,繞過 Nginx 的限制。
攻擊流程圖解
graph LR C[C] A[攻擊者傳送偽造請求] --> B(Nginx 轉發請求); B --> C{後端伺服器支援 h2c?}; C -- 支援 --> D[連線升級為 HTTP/2]; C -- 不支援 --> E[攻擊失敗]; D --> F[繞過 Nginx 存取 /flag];
攻擊範例
攻擊者可以使用 curl 等工具傳送以下請求:
curl -k -v -X GET https://localhost/ -H "Upgrade: h2c" -H "Connection: Upgrade, HTTP2-Settings"
如果後端伺服器支援 h2c,此請求將會觸發連線升級,使攻擊者能夠繞過 Nginx 的限制。
安全設定建議
為避免此類別攻擊,除非絕對必要,否則應移除或限制 proxy_set_header Upgrade
和 proxy_set_header Connection
指令。
以下提供安全的 Nginx 設定範例:
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/privkey.pem;
location / {
proxy_pass http://backend:9999;
proxy_http_version 1.1;
# 移除或限制以下標頭,除非絕對必要
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection $http_connection;
}
location /flag {
deny all;
}
}
如果必須使用 WebSocket 或 HTTP/2 升級,請確保後端伺服器已正確設定安全性,與不會允許濫用這些標頭來存取未經授權的資源。
上述程式碼片段展示瞭如何正確設定 Nginx 反向代理,以避免 h2c 挾帶攻擊。關鍵在於移除或限制 proxy_set_header Upgrade
和 proxy_set_header Connection
指令,防止攻擊者利用這些標頭操控後端伺服器的連線升級。這個設定適用於所有使用 Nginx 作為反向代理的場景,特別是當後端伺服器可能支援 h2c 時,更應提高警覺。