一 使用最新版
建議使用最新版的 Nginx,對於已經部署的 Nginx,要及時更新到最新版本,以確保所有已知的安全漏洞都已修補。
Nginx 下載地址:nginx.org/en/download…
二 限制連線數量
Nginx 可以透過 limit_conn_zone 和 limit_conn 兩個元件來對客戶端訪問目錄和檔案的訪問頻率和次數進行限制,兩個模組都能夠對客戶端訪問進行限制,具體如何使用要結合公司業務環境進行配置。
舉個簡單的例子:
http { limit_conn_zone $binary_remote_addr zone=ops:10m; # ... server { listen 80; server_name www.javaboy.org; location / { limit_conn ops 1; #這將指定一個地址只能同時存在一個連線。“one” 與上面的對應,也可以自定義命名 limit_rate 300k; } }
這裏涉及到三個配置項:
limit_zone: 是針對每個 IP 定義一個儲存 session 狀態的容器,這個示例中定義了一個 10m 的容器,假設每個 session 的大小是 32bytes,那麼可以處理 327680 個 session。
limit_conn ops 1:限制每個 IP 只能發起一個併發連線。
limit_rate 300k: 對每個連線限速 300k. 注意,這裏是對連線限速,而不是對 IP 限速。如果一個 IP 允許兩個併發連線,那麼這個 IP 就是限速
limit_rate × 2
。
三 限制請求頻率
Nginx 可以透過限制請求頻率來防止伺服器過載,最常見的場景就是登入請求,可以透過限制請求頻率防止賬號暴力破解。
Nginx 官方版本限制 IP 的連線和併發分別有兩個模組:
limit_req_zone:用來限制單位時間內的請求數,即速率限制,採用的漏桶演算法 "leaky bucket"。
limit_req_conn 用來限制同一時間連線數,即併發限制。
舉個栗子:
http { limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; server { listen 80; location / { limit_req zone=mylimit burst=5 nodelay;; proxy_pass http://javaboy.org; } } }
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
第一個引數:$binary_remote_addr 表示透過 remote_addr 這個標識來做限制,“binary_” 的目的是縮寫記憶體佔用量,是限制同一客戶端 ip 地址。
第二個引數:zone=mylimit:10m 表示生成一個大小為 10M,名字為 mylimit 的記憶體區域,用來儲存訪問的頻次資訊。
第三個引數:rate=1r/s 表示允許相同標識的客戶端的訪問頻次,這裏限制的是每秒 1 次,還可以有比如 30r/m 的。
limit_req zone=mylimit burst=5 nodelay;
第一個引數:zone=one 設定使用哪個配置區域來做限制,與上面 limit_req_zone 裡的 name 對應。
第二個引數:burst=5,重點說明一下這個配置,burst 爆發的意思,這個配置的意思是設定一個大小為 5 的緩衝區,當有大量請求(爆發)過來時,超過了訪問頻次限制的請求可以先放到這個緩衝區內。
第三個引數:nodelay,如果設定,超過訪問頻次而且緩衝區也滿了的時候就會直接返回 503,如果沒有設定,則所有請求會等待排隊。
四 防止目錄遍歷
在 Nginx 配置中設定 autoindex off
來防止目錄遍歷攻擊。
這個一般是如果你要做檔案伺服器,根據自己的實際需求,有需要的話這個功能可以開啟,否則將之關閉即可。
location / { autoindex off; }
五 隱藏 Nginx 版本號
攻擊者如果能夠確定伺服器使用的 Nginx 版本,可能會利用這個資訊來尋找和利用已知的漏洞進行攻擊。因此,隱藏版本資訊可以提高伺服器的安全性,使攻擊者難以透過版本資訊推斷出伺服器可能存在的安全漏洞。
要隱藏 Nginx 版本號,有三個辦法,一般來說我們使用第一種方式就可以了。
修改配置檔案
在 Nginx 的配置檔案中,在 http
塊中新增以下配置:
server_tokens off;
這樣設定後,Nginx 將不會在錯誤頁面上顯示版本號。
配置完成之後,儲存配置檔案並重新載入 Nginx 以應用更改:
nginx -t # 測試配置檔案是否正確 nginx -s reload # 重新載入Nginx配置
這種方法可以隱藏錯誤頁面上的版本資訊,但可能無法完全隱藏所有響應頭中的版本資訊 。
修改 Nginx 原始碼
如果想要從根源上修改 Nginx 版本資訊,需要重新編譯 Nginx,步驟如下:
修改
src/core/nginx.h
檔案中的版本定義。修改
src/http/ngx_http_header_filter_module.c
檔案中的伺服器字串。修改
src/http/ngx_http_special_response.c
檔案中的錯誤頁面底部資訊。
修改完這些檔案後,需要重新編譯 Nginx。這樣編譯安裝後,Nginx 的版本資訊將被徹底修改 。
使用第三方模組
如果需要動態修改響應頭中的版本資訊,可以使用如 headers-more-nginx-module
模組。這個模組允許你動態地新增、修改或刪除 Nginx 的響應頭。透過這個模組,可以完全控制 Server
響應頭的內容 。
選擇哪種方法取決於你的具體需求和環境。
如果你只是想簡單地隱藏版本資訊,修改配置檔案可能是最簡單的方法。如果你需要更徹底地控制版本資訊,可能需要考慮修改原始碼並重新編譯 Nginx。
六 設定超時時間
設定 Nginx 的超時配置是非常重要的,因為它可以影響伺服器的效能和資源的有效利用。
比較常見的超時配置有四個:
keepalive_timeout:這個指令設定了與客戶端的
keep-alive
連線超時時間。如果連線在指定時間內沒有數據傳輸,Nginx 將關閉該連線。預設值通常是 75 秒。這個設定對於頻繁訪問的站點尤其重要,因為它減少了連線建立和斷開的開銷。client_body_timeout:這個指令指定了客戶端與服務端建立連線後傳送 request body 的超時時間。如果客戶端在指定時間內沒有傳送任何內容,Nginx 返回 HTTP 408(Request Timed Out)。預設值通常是 60 秒。
client_header_timeout:這個指令指定了客戶端向服務端傳送一個完整的 request header 的超時時間。如果在指定時間內沒有傳送一個完整的 request header,Nginx 返回 HTTP 408(Request Timed Out)。預設值通常是 60 秒。
send_timeout:這個指令設定了服務端向客戶端傳輸資料的超時時間。如果在指定時間內客戶端沒有接收到任何資料,連線將被關閉。預設值通常是 60 秒。
針對這四個比較常見的超時配置,鬆哥這裏也給大家一個配置案例。
keepalive_timeout
這個指令控制了客戶端與伺服器之間的連線保持活動狀態的時間。這對於減少 TCP 連線的開銷非常有用,特別是在高流量的網站上。
http { keepalive_timeout 60s; server { listen 80; server_name javaboy.org; location / { proxy_pass http://javaboy.org; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } } }
在這個配置中,keepalive_timeout
被設定為 60 秒,意味著如果 60 秒內沒有數據傳輸,連線將被關閉。
client_body_timeout
這個指令設定了客戶端傳送請求體到伺服器的超時時間。
http { client_body_timeout 10s; server { listen 80; server_name javaboy.org; location /upload { client_max_body_size 100M; client_body_timeout 30s; } } }
在這個配置中,client_body_timeout
被設定為 10 秒,適用於上傳大檔案的場景,確保如果客戶端在 30 秒內沒有完成檔案上傳,請求將被終止。
client_header_timeout
這個指令控制了客戶端傳送完整的 HTTP 請求頭到伺服器的超時時間。
http { client_header_timeout 5s; server { listen 80; server_name javaboy.org; location / { proxy_pass http://javaboy.org; } } }
在這個配置中,client_header_timeout
被設定為 5 秒,意味著如果客戶端在 5 秒內沒有傳送完整的 HTTP 請求頭,伺服器將終止連線。
send_timeout
這個指令設定了伺服器傳送響應到客戶端的超時時間。
http { send_timeout 10s; server { listen 80; server_name javaboy.org; location / { proxy_pass http://javaboy.org; proxy_read_timeout 10s; } } }
在這個配置中,send_timeout
被設定為 10 秒,適用於後端服務響應慢的場景,確保如果後端服務在 10 秒內沒有傳送資料,客戶端將收到超時響應。
七 僅允許域名訪問
限制僅允許域名訪問可以防止未授權的 IP 直接訪問伺服器,減少未備案域名解析到伺服器 IP 導致的安全風險。
這個也有三種不同的配置方式,我們逐一來看。
使用兩個 server
塊
在 Nginx 配置檔案中,你可以設定一個預設的 server 塊,它將捕獲所有不明確的域名請求,並返回 403 錯誤。然後,為特定的域名設定 server 塊。
server { listen 80 default_server; server_name _; return 403; } server { listen 80; server_name www.javaboy.org; location / { # 你的配置 } }
在這個配置中,第一個 server
塊會攔截所有不明確域名的請求,並返回 403 錯誤。第二個 server
塊則是為特定域名 www.javaboy.org
提供服務的配置。
這個配置有兩點需要注意:
如果沒有顯式宣告 default server 則第一個 server 會被隱式的設為 default server。
server_name 中的
_;
,並不是重點__
也可以,___
也可以。
使用 if
語句
還可以在特定的 server
塊中使用 if
語句來檢查 $host
變數,如果它不匹配你的域名,則返回 403 錯誤。
server { listen 80; server_name javaboy.org; location / { if ($host != 'www.javaboy.org') { return 403; } # 你的配置 } }
這種方法允許你在特定域名的 server 塊中直接控制訪問許可權,只有當 $host
變數與你的域名匹配時,纔會允許訪問。
直接禁止 IP
http { server { listen 80; server_name www.javaboy.org; ... } server { listen 80; server_name www.itboyhub.com; ... } # 直接指定 ip server_name server { listen 80; server_name 11.11.11.11; return 403; # 403 forbidden } }
這樣配置後,只有透過指定的域名才能訪問網站,直接透過 IP 地址訪問將會受到限制。
八 限制 Nginx 請求方法
透過限制特定的 HTTP 請求方法,可以減少伺服器受到自動化攻擊的風險,並且可以防止某些型別的 Web 漏洞,如 SQL 注入或跨站指令碼(XSS)攻擊。
有兩種配置方式,鬆哥來和大家逐一說明。
只允許 GET 和 POST
在 server
或 location
塊中,使用 if
語句來檢查請求方法,並返回 403 錯誤碼以拒絕其他方法。
server { listen 80; server_name javaboy.org; location / { if ($request_method !~* (GET|POST)) { return 403; } # 其他配置... } }
這種方法會拒絕所有非 GET 和 POST 的請求方法。
使用 map 模組
對於更復雜的限制邏輯,可以使用 Nginx 的 map
模組來動態設定請求方法的限制。
http { map $request_method $block_request { default 0; POST 1; PUT 1; } server { listen 80; server_name javaboy.org; location / { if ($block_request) { return 403; } # 其他配置... } } }
在這個例子中,所有 POST 和 PUT 請求都會被拒絕。
九 錯誤頁面重定向
在 Nginx 中配置錯誤頁面重定向,除了安全因素之外,還有很多好處,比如:
提升使用者體驗:透過提供更友好的錯誤頁面,可以減少使用者在遇到錯誤時的困惑和挫敗感。
增強 SEO 效果:自定義錯誤頁面可以幫助搜索引擎更好地理解網站結構,避免因錯誤頁面導致的 SEO 問題。
維護品牌形象:錯誤頁面是網站的一部分,透過自定義錯誤頁面,可以保持品牌一致性,提升專業形象。
提供錯誤資訊:自定義錯誤頁面可以提供有用的錯誤資訊或解決方案,幫助使用者理解問題所在。
在 Nginx 配置檔案中,可以使用 error_page
指令來定義特定錯誤程式碼的重定向頁面。例如,將 404 錯誤重定向到自定義的 404 頁面:
server { listen 80; server_name javaboy.org; error_page 404 /404.html; location = /404.html { root /path/to/error/pages; internal; } }
在這個配置中,當 Nginx 返回 404 錯誤時,它會顯示位於 /path/to/error/pages/404.html
的自定義錯誤頁面,而不是預設的錯誤頁面。internal
指令確保這個頁面只對 Nginx 內部請求可見,不會被外部直接訪問 。
當然,上面這個配置也可以同時列舉多個錯誤狀態碼:
error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; }
這個配置會將所有 500 系列錯誤重定向到 /50x.html
,並顯示位於 /usr/share/nginx/html/50x.html
的自定義錯誤頁面 。
十 日誌保留半年
保留 Nginx 日誌半年的原因有很多,比如:
安全審計:日誌檔案可以用於安全審計,幫助分析和追蹤潛在的攻擊或異常行為。
故障排查:在系統出現故障時,日誌檔案是診斷問題的重要工具,可以幫助快速定位問題原因。
效能監控:透過分析日誌,可以瞭解網站的訪問情況和效能瓶頸,從而進行相應的最佳化。
合規性要求:某些行業法規可能要求保留一定期限的日誌記錄,以滿足合規性檢查。
要配置 Nginx 日誌保留半年,通常需要使用 logrotate
工具來實現日誌檔案的定期輪換和壓縮。
這個工具配置並不難,鬆哥給大家舉個栗子。
在 /etc/logrotate.d/
目錄下建立一個名為 nginx
的配置檔案,內容如下:
/var/log/nginx/*.log { daily rotate 180 missingok notifempty compress delaycompress sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` endscript }
這個配置會每天檢查 Nginx 日誌檔案,並將它們保留 180 天(約 6 個月),然後自動壓縮舊的日誌檔案。postrotate
部分的命令會在日誌輪換後重新開啟 Nginx 日誌檔案,以便繼續記錄新的日誌資訊。
透過這些配置,我們可以確保 Nginx 的日誌檔案被保留半年,同時舊的日誌檔案會被壓縮以節省磁碟空間。
十一 設定緩衝區
Nginx 的緩衝區溢位攻擊是一種常見的安全漏洞,它發生在程式試圖向一個緩衝區寫入超出其預分配大小的資料時。
這種攻擊可能導致資料覆蓋了相鄰的記憶體區域,可能破壞程式的執行流程,甚至可以被惡意攻擊者利用來執行惡意代碼。
爲了防止緩衝區溢位類攻擊事件,可以設定客戶端請求體、請求頭和客戶端最大請求體的緩衝區大小。
配置方式如下:
client_body_buffer_size 1K; client_header_buffer_size 1k; client_max_body_size 1k; large_client_header_buffers 2 1k;
這四行配置含義如下:
client_body_buffer_size 1K;
:這條指令設定了 Nginx 用來讀取客戶端請求體(比如 POST 請求中的資料)的緩衝區大小。在這個例子中,緩衝區大小被設定為 1KB。如果請求體的大小超過了這個緩衝區的大小,Nginx 會使用磁碟來暫存超出部分的資料。client_header_buffer_size 1k;
:這條指令定義了 Nginx 用來讀取客戶端 HTTP 請求頭部的緩衝區大小。這裏設定的大小是 1KB。如果請求頭部的大小超過了這個緩衝區的大小,Nginx 會使用large_client_header_buffers
定義的緩衝區。client_max_body_size 1k;
:這條指令限制了 Nginx 伺服器願意接收的最大請求體大小。如果客戶端傳送的請求體超過了這個大小(在這個例子中是 1KB),Nginx 將返回一個 413(Request Entity Too Large)錯誤。large_client_header_buffers 2 1k;
:這條指令定義了 Nginx 用於處理大於client_header_buffer_size
指定大小的請求頭的緩衝區數量和大小。這裏配置了 2 個大小為 1KB 的緩衝區。當請求頭的大小超過了client_header_buffer_size
定義的緩衝區大小時,Nginx 會使用這兩個額外的緩衝區來處理請求頭。
這些配置對於防止緩衝區溢位攻擊和處理大請求都是非常重要的。
十二 使用普通使用者啟動
在 Linux 系統中,只有 root 使用者或者具有特定許可權的使用者才能繫結 1024 以下的埠,如 80 埠(HTTP)和 443 埠(HTTPS)。
如果 Nginx 以 root 使用者執行,它將擁有過高的許可權,這可能會帶來安全風險。因此,爲了最小化許可權,通常會建立一個普通使用者來執行 Nginx,以減少潛在的安全漏洞。
配置方式如下:
建立使用者
首先,你需要建立一個普通使用者和使用者組,例如 nginx
。
groupadd nginx useradd -g nginx -d /usr/local/nginx nginx
這裏建立了一個名為 nginx
的使用者和組,並設定了使用者的家目錄。
授權訪問
確保新使用者有權訪問 Nginx 的配置檔案、日誌檔案和伺服器檔案。
chown -R nginx:nginx /usr/local/nginx/
這條命令將 Nginx 目錄及其所有子目錄和檔案的所有權更改為新建立的 nginx
使用者和組。
配置Nginx
編輯 Nginx 配置檔案(通常位於 /etc/nginx/nginx.conf
),設定 user
指令以指定 Nginx 工作程序的使用者。
user nginx;
這行配置指定 Nginx 應該以 nginx
使用者的身份執行。
設定許可權
如果需要,可以使用 setcap
命令賦予 Nginx 監聽 1024 以下埠的能力,而不需要以 root 使用者執行。
setcap cap_net_bind_service=+ep /usr/local/nginx/sbin/nginx
這個命令允許 Nginx 以普通使用者身份繫結到 80 和 443 埠。
啟動Nginx
使用普通使用者啟動 Nginx。
su - nginx /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
這裏首先切換到 nginx
使用者,然後啟動 Nginx 服務。
驗證
檢查 Nginx 是否以普通使用者啟動。
ps -ef | grep nginx
這條命令將顯示 Nginx 的程序資訊,你可以驗證它是否以 nginx
使用者執行。