Nginx禁止使用IP直接访问服务器上相应端口
标签搜索

Nginx禁止使用IP直接访问服务器上相应端口

lishengxie
2024-05-11 / 0 评论 / 23 阅读 / 正在检测是否收录...

起因

我的服务器中部署了一个typecho博客和两个使用docker容器的服务,其中docker容器使用端口映射,将容器中的端口映射到宿主机上的端口实现访问。

一次偶然机会发现服务器上的服务可以通过IP+端口的方式直接访问,如果有未备案的域名解析到我们服务器的IP,可能会导致云服务器厂商关停我们的服务造成一些问题。因此,我们需要禁止通过IP+端口直接访问服务。

Nginx 配置

这里的三个服务通过nginx进行转发,对不同server_name的请求会直接转发到对应的服务进程。因此,这里有限考虑使用nginx配置来禁止IP+端口的访问。服务器上主要开放了两个端口,80和443,分别用于HTTP和HTTPS请求,在实际进行相应配置时二者也有所不同。

80 端口

对于80端口,我们在nginx.conf中添加如下配置。具体原理在于,当根据listen无法得到最佳匹配时,nginx会使用请求中的Host值匹配server_name,匹配顺序可以参考这篇博客。IP+端口进行请求时匹配到下面的server配置,直接返回403错误信息。

server {
    listen 80 default_server;
    server_name  _;    
    return 403;
}

443端口

由于使用了HTTPS协议,因此还需要禁止通过IP+443端口的访问方式。具体参考了下面的博客:

具体来说,Nginx 上对于 SSL 服务器在不配置证书的时候会出现协议错误,哪怕端口上配置了其他网站也会报错。因此,我们需要随便生成一个证书进行配置,生成 SSL 证书可以使用这个网站https://myssl.com/create_test_cert.html。在nginx.conf中添加如下配置:

server {
    listen 80 default;
    listen 443 default_server;
    #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
    #error_page 404/404.html;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/private.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497  https://$host$request_uri;
    #SSL-END
    server_name _;
    return 403;
}

配置完成后重载 Nginx 配置。

$ nginx -t
$ nginx -s reload

Docker容器问题

Docker容器通过端口映射实现服务的对外可用性,这里是通过-p host_port:container_port实现容器上的端口到宿主机上端口的映射。具体来说,以容器的80端口映射到宿主机的8080端口为例,docker容器运行时使用了-p 8080:80,Nginx中监听了80端口,并在对应域名访问时将请求转发到服务器的8080端口。

location / {
    proxy_pass http://host_ip:8080;
}

但是,在根据上面的配置禁止了直接使用IP+80/443端口访问的方式后,发现host_ip:8080仍然能够访问到docker容器中的服务。查询相关资料修改了iptables路由表和sfw防火墙规则后,仍然无法解决问题。防火墙上没有打开端口,但仍然可以访问。最后通过查找资料发现是docker自身的原因,下面是docker官方的介绍:

If you don't specify an IP address (i.e., -p 80:80 instead of -p 127.0.0.1:80:80) when publishing a container's ports, Docker publishes the port on all interfaces (address 0.0.0.0) by default. These ports are externally accessible. This also applies if you configured UFW to block this specific port, as Docker manages its own iptables rules. Read more

大致意思是说docker容器中设置端口映射时如果没有指定宿主机IP,那么默认映射到0.0.0.0,即所有IP都可以访问。并且由于Docker镜像自行管理其路由表规则,设置宿主机防火墙也不起作用。知道原因后,我们只需要修稿docker容器的端口映射即可,对于正在运行的docker容器,修改方式参考如下博客,修改对应容器的/var/lib/docker/containers/{container_id}/hostconfig.json中的PostBindings->HostIp,HostIp设置为127.0.0.1即可。

参考资料

1

评论 (0)

取消