共计 3831 个字符,预计需要花费 10 分钟才能阅读完成。
IP白名单限制这个,这个限制在调用第三方平台接口时,很常见,比如一些验证码平台,微信平台,支付接口等。。。所以今天撸一个IP白名单控制,此处白名单存在本地,因为redis模块还没开始看。。。
IP白名单
在nginx中,可以使用allow/deny指令来限制一个ip或一个子网段来限制
Syntax: allow address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except
Syntax: deny address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except
样例demo
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
deny all;
}
lua-resty-iputils
在openresty中处理IP,则需要一个能解析ip的方法,此处可以使用lua-resty-iputils模块来实现
init阶段处理数据cache
[root@nginx-cluster conf.d]# cat /usr/local/openresty/nginx/lua/ip_acl.lua
local iputils = require("resty.iputils")
iputils.enable_lrucache()
local whitelist_ips = {
"10.10.10.0/24",
}
whitelist = iputils.parse_cidrs(whitelist_ips)
access阶段进行控制
server {
listen 8086;
location /sayHi {
access_by_lua_block {
local iputils = require("resty.iputils")
local res, err = iputils.ip_in_cidrs(ngx.var.remote_addr, whitelist)
if not res then
ngx.log(ngx.INFO, "ip acl err: ", err)
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
content_by_lua_block {
ngx.say("hello xadocker!")
}
}
}
此时测试下,博主本机网段:192.168.44.0/24,上面白名单放行的10.10.10.0/24,所以
[root@nginx-cluster conf.d]# curl 192.168.44.145:8086/sayHi
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty/1.17.8.2</center>
</body>
</html>
# 对应的日志
2021/05/17 23:54:00 [info] 31754#0: *1 [lua] access_by_lua(ip.conf:12):5: ip acl err: nil, client: 192.168.44.145, server: , request: "GET /sayHi HTTP/1.1", host: "192.168.44.145:8086"
2021/05/17 23:54:00 [info] 31754#0: *1 client 192.168.44.145 closed keepalive connection
将本地网段加入后即可访问
local whitelist_ips = {
"10.10.10.0/24",
"192.168.0.0/16",
}
# 增加测试机网段后即可访问
[root@nginx-cluster conf.d]# curl 192.168.44.145:8086/sayHi
hello xadocker!
iputils内的方法
enable_lrucache
syntax: ok, err = iputils.enable_lrucache(size?)
创建一个全局的LruCache对象用于缓存ip2bind查找。size
参数可选,默认4000条(大约占用每个进程1MB)。重复调用则是重置缓存
ip2bin
syntax: bin_ip, bin_octets = iputils.ip2bin(ip)
返回IPv4地址和包含每个八位字节的二进制表示形式的表的二进制表示
parse_cidr
syntax: lower, upper = iputils.parse_cidr(cidr)
返回IPv4网络最低( 网络) 和最高( 广播) 地址的二进制表示形式
parse_cidrs
syntax: parsed = iputils.parse_cidrs(cidrs)
获取一个table类型的IPV4网络表,并返回一个表格containg的表格,下面的地址
ip_in_cidrs
syntax: bool, err = iputils.ip_in_cidrs(ip, cidrs)
对string 类型ip 和table类型 cidrs 进行解析,若ip在cidrs内,则返回true或false。若返回nil,则会也会一并返回err信息
binip_in_cidrs
syntax: bool, err = iputils.binip_in_cidrs(bin_ip, cidrs)
对二进制 类型ip 和table类型 cidrs 进行解析,若ip在cidrs内,则返回true或false。若返回nil,则会也会一并返回err信息
测试样例demo
server {
listen 8086;
location /sayHi {
access_by_lua_block {
local iputils = require("resty.iputils")
local res, err = iputils.ip_in_cidrs(ngx.var.remote_addr, whitelist)
if not res then
ngx.log(ngx.INFO, "ip acl err: ", err)
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
content_by_lua_block {
local iputils = require("resty.iputils")
json = require "cjson"
ngx.say("hello xadocker!")
local bin_ip,bin_octets = iputils.ip2bin(ngx.var.remote_addr)
ngx.say("bin_ip: ",bin_ip, " bin_octets: ", bin_octets)
local lower, upper = iputils.parse_cidr("192.168.44.145/24")
ngx.say("lower: ", lower, " upper: ", upper)
local cidrs = {
"10.10.10.0/24",
"192.168.0.0/16",
}
local parsed = iputils.parse_cidrs(cidrs)
ngx.say(json.encode(parsed))
}
}
}
获得输出
[root@nginx-cluster conf.d]# curl 192.168.44.145:8086/sayHi
hello xadocker!
bin_ip: 3232246929 bin_octets: 19216844145
lower: 3232246784 upper: 3232247039
[[168430080,168430335],[3232235520,3232301055]]
ip黑名单则另建一个blacklist,之后在access阶段上反转以下即可
access_by_lua_block {
local iputils = require("resty.iputils")
local res, err = iputils.ip_in_cidrs(ngx.var.remote_addr, blacklist)
if res then
ngx.log(ngx.INFO, "ip acl err: ", err)
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
另外此处用的ngx.var.remote_addr,如果前面有代理的话则会误判,所以我们可以改下取值顺序,从header中的X-REAL-IP或X_FORWARDED_FOR中取值,最后才是ngx.var.remote_addr
access_by_lua_block {
local iputils = require("resty.iputils")
local headers=ngx.req.get_headers()
local ip = headers["X-REAL-IP"] or headers["X_FORWARDED_FOR"] or ngx.var.remote_addr
local res, err = iputils.ip_in_cidrs(ip, whitelist)
if not res then
ngx.log(ngx.INFO, "ip acl err: ", err)
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
}