动态IP黑名单与白名单实现

在互联网上,经常会遇到一些不受欢迎的HTTP请求,这些请求可能来自特定的IP地址。对于网站管理员来说,能够动态地阻止这些IP地址是非常重要的。然而,发现在互联网上并没有现成的解决方案。因此,决定自己实现一个解决方案,并在此分享给大家。

Linux下的IP阻止

在Linux系统中,通常使用iptables来阻止不需要的IP或IP范围。以下是使用iptables阻止IP的一些示例:

# 阻止特定IP iptables -A INPUT -s 0.0.0.1 -j DROP # 阻止特定IP范围 iptables -A INPUT -m iprange --src-range 0.0.0.0-0.0.0.255 -j DROP # 使用CIDR表示法阻止特定IP范围 iptables -A INPUT -s 0.0.0.0/24 -j DROP

iptables是一个非常方便的工具,如果服务器直接连接到互联网,并且没有代理或负载均衡器,那么可以使用它。但是,在网站上,使用的是AWS Elastic Beanstalk应用,运行在Linux上的Apache,并且前面有Elastic Load Balancer。因此,得到的IP地址总是负载均衡器的IP地址,只有在HTTP头部的"X-Forwarded-For"中,才能得到请求客户端的IP地址。

mod_security实现动态IP管理

由于iptables只能使用IP地址,而不能使用HTTP头部的值,因此被迫寻找替代方案。决定使用mod_security来实现这个功能。mod_security提供了"Collections"功能,它实际上是一个HashMap。IP地址是键,值是一个整数。如果值为1,则将其解释为白名单IP;如果值为2,则将其视为黑名单IP。如果键不存在,则IP既不是白名单也不是黑名单,因此会正常处理。

如果发现IP在白名单中,将不再进行进一步的检查,请求将被接受。如果发现IP在黑名单中,将断开连接,并将日志记录在modsecurity日志文件中。

要将IP添加到黑名单,可以访问应用程序的特定URL,并将IP作为参数传递。例如:

www.example.com/ip/blacklist?ip=0.0.0.1

类似地,要将IP添加到白名单,可以使用:

www.example.com/ip/whitelist?ip=0.0.0.2

要从白名单和黑名单中移除IP,可以使用:

www.example.com/ip/remove?ip=0.0.0.3

然后,最重要的是确保这些命令只有在从当前机器(即localhost)发出时才被执行。

安装mod_security后,它会创建一个名为"modsecurity.d"的目录,并加载该目录中所有带有".conf"扩展名的文件。

现在来看文件"my_rules.conf"中的源代码,该文件位于"modsecurity.d"目录中。

# 添加/移除IP到动态白名单和黑名单 - 仅限localhost # 从动态白名单和黑名单中移除 - 移除允许的变量 SecRule REQUEST_FILENAME "^/ip/remove$" "chain,phase:1,t:none,deny,nolog,status:200" SecRule REMOTE_ADDR "^127.0.0.1$" "chain,t:none" SecRule ARGS:ip "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" "t:none,initcol:ip=%{args.ip},setvar:!ip.allowed" # 添加到动态白名单 - 允许值为1 SecRule REQUEST_FILENAME "^/ip/whitelist$" "chain,phase:1,t:none,deny,nolog,status:200" SecRule REMOTE_ADDR "^127.0.0.1$" "chain,t:none" SecRule ARGS:ip "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" "t:none,initcol:ip=%{args.ip},setvar:ip.allowed=1" # 添加到动态黑名单 - 允许值为2 SecRule REQUEST_FILENAME "^/ip/blacklist$" "chain,phase:1,t:none,deny,nolog,status:200" SecRule REMOTE_ADDR "^127.0.0.1$" "chain,t:none" SecRule ARGS:ip "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" "t:none,initcol:ip=%{args.ip},setvar:ip.allowed=2" # 允许来自localhost的任何请求 SecRule REMOTE_ADDR "^127.0.0.1$" "phase:1,t:none,allow,nolog,ctl:ruleEngine=off" # 初始化IP集合,使用从x-forwarded-for或remote_addr获取的IP地址 SecRule REQUEST_HEADERS:x-forwarded-for "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" "phase:1,t:none,pass,nolog,capture,setvar:tx.client_ip=%{tx.1}" SecRule &TX:CLIENT_IP "@eq 0" "phase:1,t:none,pass,nolog,setvar:tx.client_ip=%{remote_addr}" SecRule &TX:CLIENT_IP "!@eq 0" "phase:1,t:none,pass,nolog,initcol:ip=%{tx.client_ip}" # 处理动态白名单和黑名单 # 如果IP在动态白名单中,则允许 SecRule IP:ALLOWED "@eq 1" "phase:1,t:none,allow,nolog,ctl:ruleEngine=off" # 如果IP在动态黑名单中,则丢弃 SecRule IP:ALLOWED "@eq 2" "phase:1,t:none,drop,log,logdata:'Dynamic Blacklist'"

以下是将IP添加到黑名单、白名单或从列表中移除的示例。使用Linux的curl命令来访问URL,并且只关心HTTP响应代码,可以通过使用"http_code"选项来获取。

# 黑名单几个IP curl -s -o /dev/null -I -w "%{http_code}" localhost/ip/blacklist?ip=0.0.0.1 curl -s -o /dev/null -I -w "%{http_code}" localhost/ip/blacklist?ip=0.0.0.2 curl -s -o /dev/null -I -w "%{http_code}" localhost/ip/blacklist?ip=0.0.0.3 # 白名单几个IP curl -s -o /dev/null -I -w "%{http_code}" localhost/ip/whitelist?ip=0.0.1.1 curl -s -o /dev/null -I -w "%{http_code}" localhost/ip/whitelist?ip=0.0.1.2 curl -s -o /dev/null -I -w "%{http_code}" localhost/ip/whitelist?ip=0.0.1.3 # 如果存在,则从两个列表中移除IP curl -s -o /dev/null -I -w "%{http_code}" localhost/ip/remove?ip=127.0.0.1
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485