[root@localhost nginx-1.16.1]# ./configure --help | grep http_access_module
--without-http_access_module --可以看到access模块是http_access_module模块提供的,编译时默认带此模块
访问控制模块 ,该模块可以实现简单的防火墙功能,过滤特定的主机。这个模块在我们编译nginx时会默认编译进nginx的二进制文件中,access设置就相当于设置白名单和黑名单(可以限制IP限制访问某些URL)。
如果server指令块,location指令块没有配置限制指令,那么将会继承http的限制指令,但是一旦配置了会覆盖http的限制指令。或者说作用域小的配置会覆盖作用域大的配置。access模块在内网当中允许企业服务限制访问Nginx是十分有效的。
[root@www nginx-1.16.1]# ./configure --help | grep access
--without-http_access_module disable ngx_http_access_module
只有在编译的时候指定--without-http_access_module,要不然会默认编译进去
HTTP Access模块提供了一个简单的基于host名称的访问控制。通过该模块,可以允许或禁止指定的IP地址或IP地址段访问某些虚拟主机或目录
Syntax: | allow |
---|---|
Default: | — |
Context: | http , server , location , limit_except |
允许指定网段及ip的请求, 也支持unix相关域名配置,all为允许所有
allow: 允许访问的IP或者网段,不能后面接多个IP,但是可以允许网段。
Syntax: | deny |
---|---|
Default: | — |
Context: | http , server , location , limit_except |
禁止指定ip及网段的请求,支持unix相关域名配置,all为禁止所有
deny: 拒绝访问的ip或者网段。
从语法上看,它允许配置在http指令块中,server指令块中还有locatio指令块中,这三者的作用域有所不同。
如果配置在http指令段中,将对所有server(虚拟主机)生效,配置在server指令段中,对当前虚拟主机生效,配置在location指令块中,对指定的目录生效,默认是没有防火墙,所有的IP都能进行访问。
在http指令块下配置:==》 对单ip进行限制
http {
include mime.types;
default_type application/octet-stream;
# 限制192.168.75.135这个ip访问
deny 192.168.75.135;
...
}
/usr/local/nginx/sbin/nginx -s reload --配置完记得重载配置文件。
[root@localhost ~]# curl -I 192.168.75.130 --在自己服务上访问
HTTP/1.1 200 OK
Server: nginx/1.16.0
Date: Mon, 22 Jul 2019 02:24:19 GMT
Content-Type: text/html
[root@localhost ~]# curl -I 192.168.75.130 --在192.168.75.135机器上访问
HTTP/1.1 403 Forbidden
Server: nginx/1.16.0
可以看到只对135这个ip生效了,如果有配置虚拟主机,那么这个ip将都不能访问。
对网段进行限制:
如果想让整个网段都不能访问,只需要将这个ip改为网段即可。
http {
include mime.types;
default_type application/octet-stream; --将ip改为网段
deny 192.168.75.0/24;
...
}
server指令块配置:
配置方法都是一样的,只是作用范围不同。
server {
listen 80;
server_name localhost;
deny 192.168.75.135;
...
}
在自己服务器上访问
[root@localhost ~]# curl -I 192.168.75.130
HTTP/1.1 200 OK
Server: nginx/1.16.0
Date: Mon, 22 Jul 2019 02:45:06 GMT
在192.168.75.135机器上访问:
[root@localhost ~]# curl -I 192.168.75.130
HTTP/1.1 403 Forbidden
Server: nginx/1.16.0
限制网段同上。
location指令块配置:
在location指令块配置访问控制。
这种配置是最多的,因为有时候我们要限制用户对某些文件或者目录的访问,这些文件通常是比较重要的或者私密的。
location /secret {
deny 192.168.75.135;
}
创建目录以及测试文件:
[root@localhost ~]# mkdir -p /usr/local/nginx/html/secret
[root@localhost ~]# echo "this is secret" >/usr/local/nginx/html/secret/index.html
在本机访问
[root@localhost ~]# curl 192.168.75.130/secret/index.html
this is secret
在192.168.75.135上访问
[root@localhost ~]# curl 192.168.75.130/secret/index.html
403 Forbidden
白名单设置
通过指定限制某个IP或者网段,这些形式是黑名单式的。但如果想某些服务或者文件只针对于某些IP或者网段(通常是内网)开放,那么可以使用白名单,默认拒绝,指定的放行。
location /secret {
allow 192.168.75.130;
deny all;
}
如果是deny all,allow ip,那么allow就失效了,因为是自上而下读取的,先去读取deny all。
原理:基于客户端的IP,但是对于Nginx来说,它不会管你哪个是真正的客户端,如果我们的访问不是客户端与服务端直接连接,而是通过了一层代理,比如它的代理可以负载均衡、CDN的这种代理实现,也就是我们的访问不是客户端直接访问的服务端,而是通过其他的中间件访问服务端,这时候会出现一个问题,因为Nginx的access_module它是基于remote_addr(只是连接服务端的那个IP地址)这个变量来识别客户端的IP的,那么如果一个ip通过中间件访问服务端,那么Nginx认为访问的ip就是中间件的IP,那么我们在基于IP做限制的时候,那么其实是没有作用的。所以这样的话,准确性是不高的,所以就是利用nginx的access_module有局限性。
解决方法:
①:采用别的http头信息访问控制,如HTTP_X_FORWARDED_FOR。
但是http_x_forwarded_for进行访问控制会存在问题,因为是一个协议要求的,并不是所有的cdn和代理厂商它会按照要求来做,甚至x_forwarded_for存在被修改的可能,因为只是一个头信息,所以最终还是不真实。(不是很精确的方式)
http_x_forwardded_for也是Nginx的http头变量的一个常用的变量,它和remote_addr是有区别的。不同的是,x_forwarded_for是http协议中规定头中要携带的,所以在客户端访问中间件,再访问服务端的时候,那么服务端通过Nginx会记录真实IP和中间件的IP。
格式:http_x_forwarded_for = 客户端ip,第一台代理ip,第二台代理ip,第N台代理ip....,所以http_x_forwarded_for是由一连串以逗号分隔的ip组成的。
②:结合geo模块 —— nginx的另外一个模块
③:通过HTTP自定义变量传递
因为nginx有自己的变量,我们可以在http头信息定义一个我们规定的http变量在所有上一级的设备手动把remote_addr的ip一级一级的携带过去,既能避免x_forwarded_for被修改,也能读到客户端的真实ip