nginx禁止直接ip、未配置域名访问配置

问题背景

最近偶然对线上域名配置的nginx IP进行直接访问后,发现http居然是可以通的,而https直接IP访问浏览器会报证书不安全的提示,点击详细查看发现是固定返回了nginx配置的某一个api开头的https证书给浏览器,浏览器校验证书域名与访问用的IP不一致于是报错中止了TLS握手流程。
上网一查,才发现当通过直接IP或者未绑定域名访问nginx时(其实直接IP也可以视为域名就是IP的一种情况),如果没有匹配的server_name, nginx会采用加载的第一个server_name配置处理请求。这至少会导致三个问题:

  1. IP直接HTTP方式访问nginx时,对于配置多域名的nginx服务器,其对应采用的server_name配置并不确定,即便能知道是按照配置文件字母序加载的第一个配置文件,这也不够明确,并非预期行为,应该直接禁止。
  2. IP直接HTTPS方式访问nginx会由于证书不匹配而异常终止TLS握手过程,但是客户端会得到nginx返回的默认证书,因此完全可以通过证书获得IP绑定的对应域名,这相当于暴露了IP绑定的一个域名,客户端完全可以据此使用正确的域名再次访问nginx,对于一些服务比如CDN源站,这种暴露是一个危险操作,而且任何域名暴露的真实IP都可能成为流量攻击中的一个突破点,因而默认情况下也应该避免这种情况。
  3. 国内的备案制度下,如果对于所有未预期的非备案域名返回响应,将可能导致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/

posted @ 2021-10-24 23:04  及时  阅读(4274)  评论(0编辑  收藏  举报