問題背景
最近偶然對線上域名配置的nginx IP進行直接訪問后,發現http居然是可以通的,而https直接IP訪問瀏覽器會報證書不安全的提示,點擊詳細查看發現是固定返回了nginx配置的某一個api開頭的https證書給瀏覽器,瀏覽器校驗證書域名與訪問用的IP不一致於是報錯中止了TLS握手流程。
上網一查,才發現當通過直接IP或者未綁定域名訪問nginx時(其實直接IP也可以視為域名就是IP的一種情況),如果沒有匹配的server_name, nginx會采用加載的第一個server_name配置處理請求。這至少會導致三個問題:
- IP直接HTTP方式訪問nginx時,對於配置多域名的nginx服務器,其對應采用的server_name配置並不確定,即便能知道是按照配置文件字母序加載的第一個配置文件,這也不夠明確,並非預期行為,應該直接禁止。
- IP直接HTTPS方式訪問nginx會由於證書不匹配而異常終止TLS握手過程,但是客戶端會得到nginx返回的默認證書,因此完全可以通過證書獲得IP綁定的對應域名,這相當於暴露了IP綁定的一個域名,客戶端完全可以據此使用正確的域名再次訪問nginx,對於一些服務比如CDN源站,這種暴露是一個危險操作,而且任何域名暴露的真實IP都可能成為流量攻擊中的一個突破點,因而默認情況下也應該避免這種情況。
- 國內的備案制度下,如果對於所有未預期的非備案域名返回響應,將可能導致IP端口被封禁。
禁止HTTP方式非配置域名訪問
禁止非預期域名HTTP訪問比較簡單,在ngnix conf/site-enabled 配置文件(如default.conf)中添加一下配置即可:
server
{
listen 80 default_server;
server_name _;
return 444;
}
其中defalut_server顯式指出本server為80端口的默認server, 因為是默認server,所以server_name其實可以填任意值,444為nginx自定義code,表示斷開連接不返回任何響應。
禁止HTTPS非配置域名訪問
在nginx1.19.4 及以上版本,禁止非預期域名直接訪問配置也很簡單,只需要添加443端口監聽並配置ssl_reject_handshake on即可,具體可參見NGINX 配置避免 IP 訪問時證書暴露域名
但是對於低版本nginx,需要配置對應443端口規則,還需要配置一個自簽名IP證書(不配置證書的情況下nginx -t就會直接報配置不正確),配置如下:
server
{
listen 80 default_server;
listen 443 ssl default_server;
server_name _;
ssl_certificate /usr/local/nginx/conf/ssl/ip.crt;
ssl_certificate_key /usr/local/nginx/conf/ssl/ip.key;
return 444;
}
自簽名證書生成腳本代碼參見:nginx生成符合chrome要求的自簽名證書
轉載請注明出處,原文地址: https://www.cnblogs.com/AcAc-t/p/nginx_forbid_access_by_ip_or_unexpected_host.html
參考
nginx 的 default_server 定義及匹配規則: https://segmentfault.com/a/1190000015681272
NGINX 配置避免 IP 訪問時證書暴露域名: https://zinglix.xyz/2021/10/04/nginx-ssl-reject-handshake/