背景:一个未备案的域名恶意解析到我司的服务器,导致服务器托管服务商认为我司故意不备案域名,服务商准备停掉我们的服务器的接入
解决思路:
1.通过防火墙限制域名访问
2.设置代理服务器,对于域名不是我司注册的一律限制访问
开始是希望通过防火墙去限制域名的访问,这样开销应该是最小的,但仔细想发现防火墙应该是解决不了这个需求,因为域名解析是在域名服务商那做的,在通过防火墙的时候,域名已经转换成ip地址了。
以下是摘自论坛的说法“
写道
目前的 iptables 是无法实现的
因为 iptables 工作在网络层,他看到的仅仅是数据包
domain 存放在两种数据包中
1、DNS 请求的 udp 包
2、HTTP 请求头部的 host 字段
对于 1 来说,我们得不到它,因为 DNS 请求是去放用户设置的 DNS 地址的,而且即便获得到了也做不了什么
对于 2 来说,我们虽然可以获得 host 字段具体域名,但如果在获得后再转向的话,前面的 connection 已经建立了,后面突然转向就未被了 TCP 工作原理,理论上是无法实现的
但是,利用 squid 或者 nginx 却是可以实现的,他们相当于七层代理,完全把 HTTP 请求截获,换成新的请求发向内网,得到信息再回传给客户,这样可行
至于前面有人说的 mark、tc 等,都是理论上行不通的,违反了 OSI 七层模型中 TCP 传输原理
因为 iptables 工作在网络层,他看到的仅仅是数据包
domain 存放在两种数据包中
1、DNS 请求的 udp 包
2、HTTP 请求头部的 host 字段
对于 1 来说,我们得不到它,因为 DNS 请求是去放用户设置的 DNS 地址的,而且即便获得到了也做不了什么
对于 2 来说,我们虽然可以获得 host 字段具体域名,但如果在获得后再转向的话,前面的 connection 已经建立了,后面突然转向就未被了 TCP 工作原理,理论上是无法实现的
但是,利用 squid 或者 nginx 却是可以实现的,他们相当于七层代理,完全把 HTTP 请求截获,换成新的请求发向内网,得到信息再回传给客户,这样可行
至于前面有人说的 mark、tc 等,都是理论上行不通的,违反了 OSI 七层模型中 TCP 传输原理
”
尝试了一段时间后,发现无法通过防火墙来解决这个问题,那就只能切换到nginx前端代理去禁止恶意域名访问了,其实是利用了nginx对不同来路的域名解析到不同服务器的规则实现的,以下为nginx的配置
user nginx; worker_processes 3; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; #include /etc/nginx/conf.d/*.conf; upstream cncamm{ server 127.0.0.1:8080; } server { listen 80; server_name www.cn-camm.com; access_log /var/log/nginx/cn-camm.server.access.log main; if ( $host != 'www.cn-camm.com' ){ rewrite ^/(.*)$ http://www.emapp.cn/$1 permanent; } location / { proxy_pass http://cncamm; proxy_set_header Host $host; } } }
电信人员人工检查域名后发现了我们对恶意域名采用的是转发机制,他们认为还是不行,必须要限制恶意域名的访问,于是只能对恶意域名配置403了,新的配置文件贴出来
user nginx; worker_processes 3; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; #include /etc/nginx/conf.d/*.conf; upstream cncamm{ server 127.0.0.1:8080; } server { listen 80; server_name www.cn-camm.com; access_log /var/log/nginx/cn-camm.server.access.log main; if ( $host != 'www.cn-camm.com' ){ # rewrite ^/(.*)$ http://www.emapp.cn/$1 permanent; return 403; } location / { proxy_pass http://cncamm; proxy_set_header Host $host; } }
以上配置在短时间内确实生效了,可以成功拦截到恶意域名,但是接着问题又来了,现在服务器上有两个应用,并且都同时运行,其中一个应用需要通过localhost
来访问另外一个应用,因为不希望直接通过代理后的ip预计端口访问,希望保持tomcat做前端服务器时的代码,所以localhost依然要通过nginx转发,此时发现以上配置对localhost 也进行了拦截,所以以上配置还需要修改,正常思路是在if判断中再加一层逻辑与 ,但是nginx不支持多重逻辑,此时只能使用nginx的变量了 新版配置如下: user nginx; worker_processes 3; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; #include /etc/nginx/conf.d/*.conf; upstream cncamm{ server 127.0.0.1:8080; } server { listen 80; server_name www.cn-camm.com; access_log /var/log/nginx/cn-camm.server.access.log main;
set $tag "0";以上配置对比之前只允许一个域名可以访问的配置要灵活很多,这里我们可以加入更多允许通过的域名
if ( $host !~ ^www.cn-camm.com$ ){
set $tag "$tag,1";
}
if ( $host !~ ^localhost$ ){
set $tag "$tag,2";
}
if ( $tag ~ ^0,1,2$ ){
return 403;
}
location / { proxy_pass http://cncamm; proxy_set_header Host $host; } } }