目錄
🛡? 一、常見的防刷策略分類
🔧 二、技術實現細節
? 1. 基于 IP 限流
? 2. 給接口加驗證碼
? 3. 使用 Token 限制接口訪問權限
? 4. 給接口加冷卻時間(驗證碼類經典)
? 5. 使用滑動窗口限流算法(更精細)
? 6. 使用 API 網關限流工具
? 7. 行為分析 + 機器學習防刷(高級)
🔒 三、防刷策略組合應用(實戰示例)
驗證碼接口:/send-code
🧪 四、測試建議
🧠 限流目標設定
📦 所需依賴
🧪 測試方式
? 優勢
防止接口被刷(即防止惡意頻繁訪問接口)是構建穩定、安全的后端服務的關鍵環節。接口被刷會帶來以下問題:
-
服務壓力大 → 崩潰或變慢;
-
資源被濫用 → 例如驗證碼短信費用增加;
-
用戶體驗差 → 正常用戶無法訪問服務;
-
安全隱患 → 存在撞庫攻擊、惡意爬蟲等風險。
🛡? 一、常見的防刷策略分類
類別 | 技術措施 | 舉例說明 |
---|---|---|
身份識別類 | 登錄校驗、API Key、Token、Cookie 等 | 用戶必須登錄才能訪問某些接口 |
頻率限制類 | 限流、滑動窗口、漏桶/令牌桶算法 | 每個 IP 每分鐘最多訪問5次 |
行為識別類 | 圖形驗證碼、人機驗證、行為軌跡分析 | 連續請求驗證碼時需要輸入圖形碼 |
請求來源控制 | Referer、User-Agent、IP 黑名單 | 拒絕來自非正常來源的請求 |
設備綁定 | 每個手機號/賬號最多綁定幾個設備 | 防止批量注冊賬號或虛擬機刷接口 |
🔧 二、技術實現細節
? 1. 基于 IP 限流
對訪問頻率高的 IP 設置訪問上限:
# 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。
例子:
GET /api/send-code
Authorization: Bearer eyJhbGciOiJIUzI1...
如果沒有合法 token,直接拒絕訪問,防止匿名惡意請求。
? 4. 給接口加冷卻時間(驗證碼類經典)
比如:
-
每個手機號每60秒只能發送一次驗證碼;
-
同一個賬號每天最多發送 5 次驗證碼。
用 Redis 實現:
key = f"cooldown:{phone}"
if redis.get(key):return "Too frequent", 429
redis.setex(key, 60, "1") # 設置60秒冷卻期
? 5. 使用滑動窗口限流算法(更精細)
不同于 Redis 的簡單計數,這種方式記錄多個時間戳:
時間窗口 = 1分鐘
若過去1分鐘內請求數 > 10,則拒絕
適合用在中大型項目中,Redis 或網關中集成。
? 6. 使用 API 網關限流工具
許多云服務(如 Nginx + Lua、Kong、Envoy、阿里云API網關)都有限流功能。
例子:
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
接口。
📦 所需依賴
pip install flask redis
?🧱 項目結構
rate_limit_project/
├── app.py # Flask主程序
└── limiter.py # 滑動窗口限流模塊
🔧 limiter.py(滑動窗口限流核心邏輯)
# limiter.pyimport time
import redisr = 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(主接口邏輯)
# app.pyfrom flask import Flask, request, jsonify
from limiter import is_allowedapp = Flask(__name__)@app.route('/send-code', methods=['GET'])
def send_code():ip = request.remote_addrif 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
:
curl http://localhost:5000/send-code
第 6 次起應該會返回:
{"code": 429,"msg": "請求太頻繁,請稍后再試"
}
? 優勢
-
基于時間戳的滑動窗口比簡單計數更精準;
-
Redis 存儲時間戳,自動過期,性能高;
-
可輕松擴展:按用戶 ID、IP、Token 等限流。