Openresty IP白名单限制

1,450次阅读
没有评论

共计 3831 个字符,预计需要花费 10 分钟才能阅读完成。

Openresty IP白名单限制

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
        }

正文完
 
xadocker
版权声明:本站原创文章,由 xadocker 2021-05-17发表,共计3831字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)