Flask中应结合User-Agent白名单与行为分析(如空UA+无Referer)识别恶意请求,优先使用Flask-Limiter做IP级频率限制并配置X-Forwarded-For解析,避免硬编码黑名单或手写中间件。

Flask里怎么识别并拦截恶意User-Agent
靠User-Agent字符串本身不能防爬,但能筛掉最懒的爬虫。关键是别只做字符串匹配,得结合行为判断。
常见错误是写死黑名单,比如一看到python-requests就abort(403)——这会误杀内部健康检查、监控探针,甚至某些合法 SDK。
- 优先用白名单:只放行已知合规的浏览器
User-Agent前缀(如Mozilla/5.0、Chrome/、Safari/),其余默认放行(不是拦截) - 真正要拦的,是明显异常的组合:比如
User-Agent为空 +Accept头是*/*+ 没有Referer - 别在
before_request里反复正则匹配全量User-Agent字符串,提取关键标识即可,例如:if 'scrapy' in request.headers.get('User-Agent', '').lower():
用Flask-Limiter做IP级请求频率限制
Flask-Limiter是目前最稳的选择,底层支持Redis和内存存储,比手写计数器靠谱得多。
容易踩的坑是直接按request.remote_addr限流——Nginx反代后这个值永远是127.0.0.1,必须配trusted_proxies并读X-Forwarded-For。
立即学习“Python免费学习笔记(深入)”;
华为云 Python SDK 查询工具。自动发现已安装 SDK 的服务包、Client类、API 方法、入参详情、类信息(__init__ 参数、属性、类型、描述),支持关键字搜索,快速定位目标 API 使用方法。
- 初始化时指定
key_func,不要依赖默认的get_remote_address:limiter = Limiter(key_func=lambda: request.headers.get('X-Real-IP', request.remote_addr)) - 接口级限流用装饰器,但注意:如果路由带变量(如
/api/item/<int:id>),默认会把每个id当独立key;需显式聚合:@limiter.limit("5 per minute", key_func=lambda: request.endpoint) - 内存模式仅适合开发调试,生产必须连
Redis,否则多进程下计数不同步
为什么单纯靠User-Agent+频率限制依然会被绕过
这两招对自动化脚本有效,但对真人操作的“云打码+代理池+浏览器指纹模拟”基本无效。
真正起作用的是叠加信号:比如同一IP在1分钟内触发3次User-Agent异常 + 2次429响应 + 1次非标准Accept-Encoding,才升级为临时封禁。
- 别把防御逻辑全塞进一个中间件,拆成独立函数,方便后续接入风控规则引擎
- 记录原始
User-Agent到日志时,记得截断(避免日志爆炸),例如只存前64字符:logger.info("UA: %s", ua[:64]) - 频率限制的阈值别设太激进,
10 per minute对移动端API可能误伤;建议先开日志观察真实流量分布,再定策略
不推荐手写中间件做这些事
自己解析User-Agent字符串、维护IP计数字典、处理并发写冲突——这些轮子早被Flask-Limiter和user-agents库覆盖了。
更麻烦的是边界情况:比如IPv6地址格式、Cloudflare转发的CF-Connecting-IP头、HTTP/2里头字段大小写混用……全得自己兜底。
- 要用
user-agents库识别设备类型,别用re.search(r'iPhone', ua)这种硬编码 - 所有限流配置必须可热更新,别写死在代码里;
Flask-Limiter支持从配置对象动态加载DEFAULT_LIMITS - 记住:爬虫对抗本质是成本博弈。你加一层校验,对方就多花5分钟绕过;重点该放在让高价值数据访问路径更难批量获取,而不是拦住所有非浏览器请求

















