Redis怎么用来限制IP访问,设置IP白名单黑名单那些事儿
- 问答
- 2025-12-28 02:01:40
- 3
主要基于Redis的常用数据结构和命令在访问控制场景下的应用,参考了常见的网络开发实践和Redis官方文档中关于键(key)和过期时间(expire)的基本概念。)
在日常的网站或应用运营中,我们经常会遇到需要控制某些IP地址访问的情况,防止恶意爬虫频繁抓取数据,或者限制某个用户在短时间内重复登录尝试,又或者只允许特定的内部IP访问管理后台,自己写程序把IP地址存到数据库里当然可以,但当访问量很大、判断频率很高时,频繁读写数据库会给数据库造成很大压力,这时候,Redis就能大显身手了,因为它把数据放在内存里,读写速度极快,特别适合处理这种需要快速判断的“是”或“否”的问题。
Redis具体是怎么做的呢?核心就是利用它几种简单的数据结构和两个关键特性:超时过期和原子操作。
基础武器:使用键值对和过期时间做频率限制
这是最常见的一种用法,目的是限制某个IP在特定时间内的访问次数,比如一分钟内不能超过60次,这更像是一个“临时限流”的策略。
方法很简单:我们以IP地址为关键字(key),以一个计数器作为值(value),每次这个IP来访问,我们就让这个计数器增加1,我们给这个key设置一个生存时间,比如60秒,这样,第一次访问时,这个键被创建,值设为1,60秒后自动消失,如果这个IP在60秒内访问了第61次,我们检查到它的计数器已经超过60了,就拒绝这次访问。
在Redis中,实现这个逻辑的命令主要是 INCR 和 EXPIRE。INCR 命令能把一个键的值增加1,如果这个键不存在,它会先初始化为0再加1,非常方便,我们可以这样操作:
- 当IP为
168.1.100第一次访问时,我们执行INCR 192.168.1.100,Redis返回结果1。 - 我们执行
EXPIRE 192.168.1.100 60,告诉Redis这个键60秒后过期。 - 下次同一IP再来,继续
INCR,值变成2。 - 在每次
INCR操作后,我们检查一下返回值,如果大于60,就说明超限了,触发限制逻辑。
这里有个小技巧,为了避免每次设置过期时间,我们可以使用一个更强大的命令:SETEX,它能在设置值的同时直接指定过期时间,或者使用 INCR 和 EXPIRE 的组合,但要确保它们一起执行(可以用Redis的事务或者Lua脚本来保证原子性,避免设了值却忘了设过期时间的尴尬)。
核心装备:使用集合打造白名单和黑名单
频率限制是软性的,而白名单和黑名单则是硬性的“允许”与“禁止”,Redis的集合(Set)数据结构非常适合干这个活儿,集合的特点是无序,但里面的每个成员都是唯一的,正好符合IP地址不重复的需求。
-
黑名单(Blacklist):顾名思义,就是把要封禁的IP地址扔进一个集合里,我们可以给这个集合起个名字,
ip:blacklist。- 添加黑名单:使用
SADD命令,比如要封禁0.0.5和0.0.6,就执行SADD ip:blacklist 10.0.0.5 10.0.0.6。 - 查询是否在黑名单:使用
SISMEMBER命令,当有IP访问时,执行SISMEMBER ip:blacklist 10.0.0.5,如果返回1,说明这个IP在黑名单里,直接拒绝访问;返回0则不在。 - 移除黑名单:使用
SREM命令。SREM ip:blacklist 10.0.0.5。
- 添加黑名单:使用
-
白名单(Whitelist):和黑名单相反,只有在这个名单里的IP才允许访问,逻辑完全一样,只是集合的名字换成了
ip:whitelist,在实际检查时,先判断IP是否在ip:whitelist中,如果不在,即便不在黑名单也拒绝访问,白名单通常用于对安全性要求极高的场景,比如数据库后台、API网关的管理端点等。
使用集合的好处是,管理起来非常直观和灵活,我们可以随时添加、删除名单中的IP,而且判断速度极快,因为Redis的集合内部使用哈希表实现,查询某个成员是否存在的时间复杂度是O(1),几乎是瞬间完成。
高级组合技:有序集合应对复杂场景
我们可能想要一个“临时黑名单”,某个IP在短时间内触发了太多次频率限制,我们想把它自动加入黑名单,但只封禁一小时,这时候,单纯的集合就不够用了,因为它不能自动过期,Redis的另一个数据结构——有序集合(Sorted Set)可以解决这个问题。
有序集合比普通集合多了一个分数(score)的概念,我们可以把IP地址作为成员(member),把封禁到期的时间戳(例如当前时间戳+3600秒)作为分数(score)。
- 添加临时封禁:使用
ZADD命令。ZADD ip:temp_blacklist 1640995200 10.0.0.5,意思是将IP0.0.5封禁到时间戳1640995200(这是一个示例时间)为止。 - 检查是否被封禁:检查分两步:
- 首先用
ZSCORE命令查一下这个IP的分数(到期时间),如果查不到,说明不在临时黑名单里。 - 如果查到了,就拿这个分数(到期时间)和当前时间戳比较,如果到期时间大于当前时间,说明封禁还在有效期内,拒绝访问;如果小于当前时间,说明已经解封了,可以允许访问,并且我们可以用
ZREM命令把这个过期的条目删掉,清理空间。
- 首先用
- 自动清理:Redis有序集合还支持按分数范围删除元素,我们可以定期执行一个任务,使用
ZREMRANGEBYSCORE命令,把所有分数小于当前时间戳的成员删除掉,实现自动清理过期黑名单条目。
总结一下
用Redis来做IP访问控制,其实就是“杀鸡用牛刀”——用高性能的工具解决一个看似简单但要求速度的问题。
- 简单限流:用
INCR+EXPIRE。 - 永久性黑白名单:用
Set和SISMEMBER。 - 有时效性的黑白名单:用
Sorted Set,把过期时间当分数用。
在实际应用中,这些方法通常会结合使用,比如先过白名单,再检查黑名单,最后过频率限制,所有的判断逻辑都可以写在一个Lua脚本里,由Redis原子性地执行,确保高效和准确,这样一来,我们就能用一个轻量级的方法,有效地管理起网络的入口安全。

本文由符海莹于2025-12-28发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/69757.html
