目录
[🛡️ 一、常见的防刷策略分类](#🛡️ 一、常见的防刷策略分类)
[🔧 二、技术实现细节](#🔧 二、技术实现细节)
[✅ 1. 基于 IP 限流](#✅ 1. 基于 IP 限流)
[✅ 2. 给接口加验证码](#✅ 2. 给接口加验证码)
[✅ 3. 使用 Token 限制接口访问权限](#✅ 3. 使用 Token 限制接口访问权限)
[✅ 4. 给接口加冷却时间(验证码类经典)](#✅ 4. 给接口加冷却时间(验证码类经典))
[✅ 5. 使用滑动窗口限流算法(更精细)](#✅ 5. 使用滑动窗口限流算法(更精细))
[✅ 6. 使用 API 网关限流工具](#✅ 6. 使用 API 网关限流工具)
[✅ 7. 行为分析 + 机器学习防刷(高级)](#✅ 7. 行为分析 + 机器学习防刷(高级))
[🔒 三、防刷策略组合应用(实战示例)](#🔒 三、防刷策略组合应用(实战示例))
[🧪 四、测试建议](#🧪 四、测试建议)
[🧠 限流目标设定](#🧠 限流目标设定)
[📦 所需依赖](#📦 所需依赖)
[🧪 测试方式](#🧪 测试方式)
[✅ 优势](#✅ 优势)
防止接口被刷(即防止恶意频繁访问接口)是构建稳定、安全的后端服务的关键环节。接口被刷会带来以下问题:
-
服务压力大 → 崩溃或变慢;
-
资源被滥用 → 例如验证码短信费用增加;
-
用户体验差 → 正常用户无法访问服务;
-
安全隐患 → 存在撞库攻击、恶意爬虫等风险。
🛡️ 一、常见的防刷策略分类
类别 | 技术措施 | 举例说明 |
---|---|---|
身份识别类 | 登录校验、API Key、Token、Cookie 等 | 用户必须登录才能访问某些接口 |
频率限制类 | 限流、滑动窗口、漏桶/令牌桶算法 | 每个 IP 每分钟最多访问5次 |
行为识别类 | 图形验证码、人机验证、行为轨迹分析 | 连续请求验证码时需要输入图形码 |
请求来源控制 | Referer、User-Agent、IP 黑名单 | 拒绝来自非正常来源的请求 |
设备绑定 | 每个手机号/账号最多绑定几个设备 | 防止批量注册账号或虚拟机刷接口 |
🔧 二、技术实现细节
✅ 1. 基于 IP 限流
对访问频率高的 IP 设置访问上限:
python
# Redis限流示例:每个IP每分钟只能访问10次
ip_key = f"limit:{ip_address}"
count = redis.incr(ip_key)
if count == 1:
redis.expire(ip_key, 60) # 设置1分钟过期
if count > 10:
return "Too many requests", 429
✅ 适合接口:短信验证码、注册、登录、敏感操作。
✅ 2. 给接口加验证码
当用户触发"频繁操作"行为时,加一道图形验证码或滑块验证。
示例:
-
连续点击"获取验证码"按钮超过2次 → 弹出图形验证码
-
失败登录超过5次 → 要滑动验证
常用方案:
验证类型 | 说明 |
---|---|
图形验证码 | 传统的"输入下图文字"方式 |
滑动验证码 | 腾讯云、极验验证码等 |
点选图标 | "请点选所有的猫" 等人机验证 |
✅ 3. 使用 Token 限制接口访问权限
很多接口只能在登录状态下访问,或需要传递一个有效的 API token。
例子:
bash
GET /api/send-code
Authorization: Bearer eyJhbGciOiJIUzI1...
如果没有合法 token,直接拒绝访问,防止匿名恶意请求。
✅ 4. 给接口加冷却时间(验证码类经典)
比如:
-
每个手机号每60秒只能发送一次验证码;
-
同一个账号每天最多发送 5 次验证码。
用 Redis 实现:
python
key = f"cooldown:{phone}"
if redis.get(key):
return "Too frequent", 429
redis.setex(key, 60, "1") # 设置60秒冷却期
✅ 5. 使用滑动窗口限流算法(更精细)
不同于 Redis 的简单计数,这种方式记录多个时间戳:
bash
时间窗口 = 1分钟
若过去1分钟内请求数 > 10,则拒绝
适合用在中大型项目中,Redis 或网关中集成。
✅ 6. 使用 API 网关限流工具
许多云服务(如 Nginx + Lua、Kong、Envoy、阿里云API网关)都有限流功能。
例子:
bash
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=5r/s;
server {
location /api/ {
limit_req zone=req_limit burst=10 nodelay;
}
}
含义:同一 IP 每秒最多访问5次,最多可突发10次。
✅ 7. 行为分析 + 机器学习防刷(高级)
企业常用方式:
-
结合访问路径、时间间隔、鼠标轨迹、设备ID、IP地区等特征;
-
判断是否为脚本行为,自动拉入风控系统;
如支付宝、微信等都会对登录、转账等操作做 AI 风控。
🔒 三、防刷策略组合应用(实战示例)
验证码接口:/send-code
类型 | 策略 |
---|---|
限速 | 每个手机号每分钟一次,IP 每小时最多 20 次 |
身份 | 登录后才允许请求验证码(防刷注册) |
图形验证码 | 多次请求后弹出图形验证 |
阈值 | 每个账号/手机号每天最多请求 5 次 |
🧪 四、测试建议
-
自己用脚本模拟高频调用接口,观察日志和限流是否生效;
-
使用 Apache Benchmark (
ab
) 或locust
进行压力测试; -
查看 Redis、网关是否正确记录并限制请求。
下面是一个使用 Flask + Redis 实现滑动窗口限流的接口示例,可以有效防止恶意刷接口请求,比如"短信验证码接口"。
🧠 限流目标设定
规则: 每个 IP 地址在过去 60 秒内最多访问 5 次 /send-code
接口。
📦 所需依赖
bash
pip install flask redis
🧱 项目结构
bash
rate_limit_project/
├── app.py # Flask主程序
└── limiter.py # 滑动窗口限流模块
🔧 limiter.py(滑动窗口限流核心逻辑)
python
# limiter.py
import time
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
def is_allowed(ip: str, max_requests=5, window_seconds=60) -> bool:
now = int(time.time())
key = f"rate_limit:{ip}"
# 移除窗口外的时间戳
r.zremrangebyscore(key, 0, now - window_seconds)
# 当前请求数量
current_count = r.zcard(key)
if current_count >= max_requests:
return False
# 添加当前时间戳(score 和 value 都是当前时间)
r.zadd(key, {str(now): now})
r.expire(key, window_seconds)
return True
🚀 app.py(主接口逻辑)
python
# app.py
from flask import Flask, request, jsonify
from limiter import is_allowed
app = Flask(__name__)
@app.route('/send-code', methods=['GET'])
def send_code():
ip = request.remote_addr
if not is_allowed(ip):
return jsonify({"code": 429, "msg": "请求太频繁,请稍后再试"}), 429
# 模拟发送短信验证码
return jsonify({"code": 200, "msg": "验证码已发送(假装的😄)"})
if __name__ == '__main__':
app.run(debug=True)
🧪 测试方式
连续请求超过 5 次 /send-code
:
bash
curl http://localhost:5000/send-code
第 6 次起应该会返回:
bash
{
"code": 429,
"msg": "请求太频繁,请稍后再试"
}
✅ 优势
-
基于时间戳的滑动窗口比简单计数更精准;
-
Redis 存储时间戳,自动过期,性能高;
-
可轻松扩展:按用户 ID、IP、Token 等限流。