当前位置: 首页 > article >正文

使用 Flask-Limiter 和 Nginx 实现接口访问次数限制

在现代 Web 应用中,针对敏感接口(如短信验证码、登录接口等)的访问次数限制至关重要。通过设置合理的限流策略,可以有效防止接口滥用,避免过多的资源消耗,并提升安全性。本文将通过 Nginx 和 Flask-Limiter 为 Flask 应用实现 IP 级别的限流,同时确保限流基于客户端的真实 IP 地址,而非内网地址如 172.17.0.1

1. 使用 Nginx 作为反向代理

Nginx 通常作为 Web 应用的反向代理,接收来自客户端的请求并将其转发到后端的应用程序(如 Flask)。由于 Nginx 在中间充当代理角色,后端应用获取到的可能是 Nginx 或 Docker 容器的内网 IP(如 172.17.0.1),因此获取客户端真实 IP 就显得非常重要。

Nginx 配置中的关键参数

我们可以通过一些配置,将客户端的真实 IP 地址传递给 Flask 应用:

# 重定向 HTTP 到 HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

# 处理 HTTPS 请求
server {
    listen 443 ssl http2;
    server_name example.com;

    # SSL 证书配置
    ssl_certificate    /path/to/your/fullchain.pem;
    ssl_certificate_key    /path/to/your/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers EECDH+AESGCM:EECDH+CHACHA20:!aNULL:!MD5:!DSS;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    add_header Strict-Transport-Security "max-age=31536000" always;

    # 反向代理到 Flask 应用的 5100 端口
    location / {
        proxy_pass http://127.0.0.1:5100;  # 将请求转发到 Flask
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 日志配置(可选)
    access_log  /path/to/log/access.log;
    error_log  /path/to/log/error.log;
}
主要参数解释
  • proxy_pass: 将请求转发到后端的 Flask 应用,通常监听在 127.0.0.1:5100 端口。
  • proxy_set_header Host $host: 将客户端请求的主机名传递给后端应用。
  • proxy_set_header X-Real-IP $remote_addr: 传递客户端的真实 IP 地址给后端应用。$remote_addr 是直接连接到 Nginx 的客户端 IP,通常是原始客户端的 IP。
  • proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for: 将经过的代理链(包括客户端真实 IP)传递给后端应用。这个头通常包含客户端的真实 IP 地址。
  • proxy_set_header X-Forwarded-Proto $scheme: 传递请求使用的协议(HTTP 或 HTTPS)给后端应用。
避免内网 IP 地址 172.17.0.1

如果您的 Flask 应用运行在 Docker 容器中,而 Nginx 也运行在同一服务器上,后端 Flask 应用接收到的 IP 可能是 172.17.0.1,这是 Docker 内网的默认网关地址。这个地址会导致所有请求都被认为来自同一个 IP,从而错误地进行限流。

通过上述 Nginx 配置中的 X-Forwarded-For 头部,我们可以将客户端的真实 IP 地址传递给 Flask,避免使用 Docker 内部的 IP(如 172.17.0.1)进行限流。

2. 使用 Flask-Limiter 实现限流

Flask-Limiter 是一个非常方便的库,用于限制 Web 应用中的接口访问次数。我们可以结合 Nginx 的配置,通过 X-Forwarded-For 获取到真实的客户端 IP,基于 IP 实现限流。

安装 Flask-Limiter

首先,确保 Flask-Limiter 已安装:

pip install flask-limiter

 基于 IP 地址限流的 Flask 代码

from flask import Flask, request, jsonify
from flask_limiter import Limiter

app = Flask(__name__)

# 获取真实客户端 IP 地址
def get_client_ip():
    # 检查是否有 X-Forwarded-For 头部
    if request.headers.getlist("X-Forwarded-For"):
        return request.headers.getlist("X-Forwarded-For")[0]  # 获取真实的客户端 IP
    else:
        return request.remote_addr  # 使用默认的 remote_addr

# 初始化 Flask-Limiter,并使用 get_client_ip 作为限流的 key_func
limiter = Limiter(
    key_func=get_client_ip,  # 使用真实的客户端 IP 进行限流
    app=app,
    storage_uri="redis://<your_redis_host>:<redis_port>/1"  # 使用 Redis 存储限流信息
)

# 定义接口,并为每个 IP 地址限制每分钟 1 次,每天最多 15 次访问
@app.route('/send_verification_code', methods=['POST'])
@limiter.limit("1 per minute; 15 per day")
def send_verification_code():
    phone_number = request.form.get('phone_number')
    machine_id = request.headers.get('Machine-Id')

    if not phone_number:
        return jsonify({"error": "手机号不能为空"}), 400
    if not machine_id:
        return jsonify({"error": "Machine-Id 不能为空"}), 400

    # 处理发送验证码的逻辑
    return jsonify({"message": "验证码发送成功"}), 200

if __name__ == '__main__':
    app.run(debug=True)
代码解释
  1. get_client_ip 函数: 用于获取真实的客户端 IP,优先使用 X-Forwarded-For 头部中的第一个 IP 地址(通常为客户端 IP),如果没有,则使用 request.remote_addr

  2. Flask-Limiter 配置: key_func 设置为 get_client_ip,确保限流基于客户端的真实 IP。storage_uri 指定 Redis 存储限流信息,避免 Flask 重启或进程切换时丢失限流数据。

  3. @limiter.limit("1 per minute; 15 per day"): 设置限流规则,限制每个 IP 每分钟只能请求一次,每天最多 15 次。

3. Redis 存储限流信息

Flask-Limiter 支持使用 Redis 存储限流信息,这样即使 Flask 应用重启,限流信息也不会丢失。通过 Redis 可以实现跨进程的限流。

Redis 连接配置
limiter = Limiter(
    key_func=get_client_ip,
    app=app,
    storage_uri="redis://:password@redis_host:6379/1"  # 使用 Redis db1
)

4. 验证限流

通过上述配置,当 Flask-Limiter 生效时,Redis 中的键将会包含真实的客户端 IP,并记录请求的访问次数。例如,Redis 中的键可能类似于:

LIMITS:LIMITER/<client_real_ip>/send_verification_code/1/1/minute

这样,限流规则是基于客户端真实 IP 地址的,避免了因 Docker 内网 IP 172.17.0.1 导致的限流错误。

5. 总结

通过 Nginx 的反向代理配置,我们可以将客户端的真实 IP 传递给 Flask 应用。结合 Flask-Limiter,可以基于客户端的真实 IP 地址,实现针对敏感接口的访问频率限制。这样不仅可以提升 Web 应用的安全性,还能有效防止滥用行为。

核心步骤总结如下:

  • Nginx 配置: 使用 X-Forwarded-ForX-Real-IP 头部传递客户端 IP,避免使用 172.17.0.1 等内网 IP。
  • Flask-Limiter: 结合 Redis 实现基于 IP 地址的访问次数限制。
  • 客户端真实 IP 获取: 通过 get_client_ip 函数确保 Flask 获取到真实的客户端 IP。

这种限流机制为 Web 应用的安全和性能提供了重要保障。


http://www.kler.cn/a/319090.html

相关文章:

  • Android Studio 将项目打包成apk文件
  • 结构体是否包含特定类型的成员变量
  • CSS多列布局:打破传统布局的束缚
  • 前端神经网络入门(三):深度学习与机器学习的关系、区别及核心理论支撑 - 以Brain.js示例
  • ctfshow-web入门-SSTI(web361-web368)上
  • flink sql + kafka + mysql 如何构建实时数仓
  • 美畅物联丨海康威视摄像机固件升级指南
  • msvcp140.dll丢失怎么办,总结6种解决msvcp140.dll丢失的方法
  • 代码随想录算法day40 | 动态规划算法part13 | 647. 回文子串,516.最长回文子序列
  • Android 模拟按键功能实现
  • 宠物智能听诊器宠物健康管理设备
  • Java中的位图和布隆过滤器(如果想知道Java中有关位图和布隆过滤器的知识点,那么只看这一篇就足够了!)
  • 分享6个icon在线生成网站,支持AI生成
  • 生信初学者教程(四):软件
  • C语言实现简单凯撒密码算法
  • springboot使用minio(8.5.11)
  • 某易易盾验证码逆向
  • vue3 选择字体的颜色,使用vue3-colorpicker来选择颜色
  • Spring Boot集成LiteFlow使用详解
  • 【可变模板参数】
  • DS18B20温度传感器模块
  • Day29笔记-Python操作pdfPython发送邮件
  • 广州C++信奥赛老师解一本通题 1389:亲戚
  • llamafactory0.9.0微调qwen2.5
  • Docker 教程:如何查看容器的最后 300 行实时日志
  • Hi.Events —— 您的全方位活动管理与票务平台