Files
zjpb.net/docs/archive/DEVELOP_v2.6.0_API_SECURITY.md
Jowe 939717fa57 feat: v2.6.0 - API安全优化和文档整合
## 核心优化
- 移除详情页自动调用博查API的逻辑,改为按需加载
- 添加基于IP的频率限制(每小时3次)
- 实现验证码防护机制(超过阈值后要求验证)
- 新增频率限制工具类 utils/rate_limiter.py

## 成本控制
- API调用减少约90%+(只在用户点击时调用)
- 防止恶意滥用和攻击
- 可配置的频率限制和验证码策略

## 文档整合
- 创建 docs/ 目录结构
- 归档历史版本文档到 docs/archive/
- 移动部署文档到 docs/deployment/
- 添加文档索引 docs/README.md

## 技术变更
- 新增依赖: Flask-Limiter==3.5.0
- 修改: app.py (移除自动调用,新增API端点)
- 修改: templates/detail_new.html (按需加载UI)
- 新增: utils/rate_limiter.py (频率限制和验证码)
- 新增: docs/archive/DEVELOP_v2.6.0_API_SECURITY.md

## 部署说明
1. pip install Flask-Limiter==3.5.0
2. 重启应用
3. 无需数据库迁移

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-06 15:54:13 +08:00

10 KiB
Raw Blame History

ZJPB v2.6.0 开发文档 - API安全优化

版本号: v2.6.0 开发日期: 2026-02-06 功能主题: 博查API调用优化 + 频率限制 + 安全防护 Git Commit: (待提交)


📋 功能概述

问题背景

v2.5及之前版本存在严重的成本浪费问题:

  • 每次访问详情页都自动调用博查API
  • 没有频率限制,容易被滥用
  • 缺少安全防护机制

优化目标

  1. 按需加载: 只在用户点击按钮时才调用API
  2. 频率限制: 每个IP每小时最多3次请求
  3. 验证码防护: 超过阈值后需要验证码
  4. 成本控制: 大幅降低无意义的API消耗

🎯 核心改进

1. 移除自动调用逻辑

修改文件: app.py:151-240

before (v2.5):

# 智能新闻更新:检查今天是否已更新过新闻
need_update = False
if not latest_news:
    need_update = True
elif latest_news.created_at.date() < today:
    need_update = True

# 如果需要更新,自动获取最新新闻
if need_update:
    searcher = NewsSearcher(api_key)
    news_items = searcher.search_site_news(...)
    # 保存到数据库

after (v2.6):

# v2.6优化移除自动调用博查API的逻辑改为按需加载
# 只获取数据库中已有的新闻不再自动调用API

news_list = News.query.filter_by(
    site_id=site.id,
    is_active=True
).order_by(News.published_at.desc()).limit(5).all()

影响: 每次页面访问减少1次API调用节省成本约95%+

2. 按需加载API

新增路由: /api/fetch-news/<code> 方法: POST 权限: 公开(有频率限制)

功能:

  • 用户点击"加载资讯"按钮时调用
  • 返回JSON格式的新闻列表
  • 前端动态渲染,无需刷新页面

3. 频率限制系统

新增文件: utils/rate_limiter.py (320行)

核心类:

  • RateLimiter: 基于内存的频率限制器
  • CaptchaVerifier: 验证码验证器
  • get_client_ip(): 获取真实IP考虑代理/CDN

限制策略:

  • 每个IP每小时最多3次请求
  • 超过限制后需要等待或完成验证码
  • 验证码要求持续30分钟

配置参数:

# 在 fetch_news_for_site() 中配置
limiter.is_rate_limited(
    client_ip,
    action='news_fetch',
    limit=3,              # 每小时3次
    window_minutes=60     # 时间窗口60分钟
)

4. 验证码集成

支持的服务:

  • simple: 简单验证(开发测试用)
  • recaptcha: Google reCAPTCHA v2/v3
  • hcaptcha: hCaptcha

集成步骤:

  1. .env中配置密钥:

    RECAPTCHA_SECRET_KEY=your-secret-key
    # 或
    HCAPTCHA_SECRET_KEY=your-secret-key
    
  2. 修改app.py中的验证器实例化:

    verifier = CaptchaVerifier(
        service='recaptcha',
        secret_key=app.config.get('RECAPTCHA_SECRET_KEY')
    )
    
  3. 前端添加验证码组件(见下文)


🔧 技术实现

前端改进

修改文件: templates/detail_new.html

1. 新闻区域显示逻辑:

<!-- 始终显示新闻区域 -->
<div class="content-block">
    <button onclick="loadNews('{{ site.code }}')">
        {% if has_news %}获取最新资讯{% else %}加载资讯{% endif %}
    </button>

    {% if news_list %}
        <!-- 显示已有新闻 -->
    {% else %}
        <!-- 显示占位提示 -->
        <div class="news-placeholder">
            点击右上角"加载资讯"按钮获取最新内容
        </div>
    {% endif %}
</div>

2. AJAX加载函数:

function loadNews(siteCode) {
    fetch(`/api/fetch-news/${siteCode}`, {
        method: 'POST',
        headers: {'Content-Type': 'application/json'}
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            // 动态渲染新闻列表
            renderNews(data.news);
            showMessage(data.message, 'success');
        } else if (data.require_captcha) {
            // 显示验证码
            showCaptchaModal();
        } else {
            showMessage(data.error, 'error');
        }
    });
}

后端改进

修改文件: app.py:185-307

流程图:

用户请求
  ↓
获取客户端IP
  ↓
检查是否需要验证码 → YES → 返回429错误
  ↓ NO
检查频率限制 → 超限 → 要求验证码 → 返回429错误
  ↓ 未超限
验证验证码(如果提供)
  ↓
记录请求
  ↓
调用博查API
  ↓
保存到数据库
  ↓
返回新闻列表

📊 性能对比

API调用次数

场景: 某个工具详情页被浏览100次

版本 自动调用 手动点击 总调用 成本
v2.5 100次 0次 100次 ¥100
v2.6 0次 ~10次 10次 ¥10

节省: 约90% API成本

频率限制效果

攻击场景: 恶意脚本每秒请求1次

版本 1小时调用 成本
v2.5 3600次 ¥3600
v2.6 3次 ¥3

防护: 99.9% 成本节省


🚀 部署指南

1. 更新依赖

pip install Flask-Limiter==3.5.0
# 或
pip install -r requirements.txt

2. 更新代码

git pull origin master
# 或手动上传更新的文件

3. 无需数据库迁移

本次更新无数据库结构变更。

4. 重启应用

# 使用1Panel或命令行
sudo supervisorctl restart zjpb

5. 验证部署

  1. 访问任意工具详情页
  2. 确认不会自动加载新闻(页面加载快了)
  3. 点击"加载资讯"按钮
  4. 确认新闻正常显示
  5. 连续点击4次确认出现频率限制提示

⚙️ 配置选项

频率限制参数

app.pyfetch_news_for_site()函数中:

# 调整限制次数和时间窗口
is_limited, remaining, reset_time = limiter.is_rate_limited(
    client_ip,
    action='news_fetch',
    limit=3,              # 改为5次更宽松
    window_minutes=60     # 改为30分钟更严格
)

# 调整验证码持续时间
limiter.require_captcha(
    client_ip,
    duration_minutes=30   # 改为60分钟更严格
)

验证码配置

使用Google reCAPTCHA:

  1. 注册并获取密钥:https://www.google.com/recaptcha/admin
  2. 配置.env:
    RECAPTCHA_SITE_KEY=your-site-key
    RECAPTCHA_SECRET_KEY=your-secret-key
    
  3. 修改app.py:
    verifier = CaptchaVerifier(
        service='recaptcha',
        secret_key=app.config.get('RECAPTCHA_SECRET_KEY')
    )
    

使用hCaptcha(国内推荐):

  1. 注册:https://www.hcaptcha.com/
  2. 配置.env:
    HCAPTCHA_SITE_KEY=your-site-key
    HCAPTCHA_SECRET_KEY=your-secret-key
    
  3. 修改app.py:
    verifier = CaptchaVerifier(
        service='hcaptcha',
        secret_key=app.config.get('HCAPTCHA_SECRET_KEY')
    )
    

🔐 安全特性

IP识别策略

支持CDN/代理场景按优先级获取真实IP

  1. X-Forwarded-For第一个IP
  2. X-Real-IP
  3. request.remote_addr

防绕过机制

  • 基于IP地址限制不依赖Cookie/Session
  • 验证码要求持续30分钟不能通过清除缓存绕过
  • 时间窗口滑动(不是固定时段)

日志记录

建议添加日志记录TODO

# 记录频率限制触发
app.logger.warning(f"Rate limit triggered: {client_ip}")

# 记录验证码验证失败
app.logger.warning(f"Captcha failed: {client_ip}")

📝 文档整合

新增目录结构:

docs/
├── README.md              # 文档索引
├── deployment/            # 部署相关文档
│   ├── DEPLOYMENT.md
│   ├── QUICK_DEPLOY.md
│   └── ...
└── archive/              # 历史版本文档
    ├── DEPLOY_v2.4.0.md
    ├── DEVELOP_v2.4.1_TAB_FEATURE.md
    ├── NEWS_FEATURE_v2.2.md
    └── WORK_PROGRESS_20250130.md

整合原因: 简化根目录,提高可维护性


🐛 已知问题和注意事项

1. 内存存储限制

当前使用内存存储频率限制数据,重启应用后清空。

生产环境建议:

  • 使用Redis存储持久化
  • 使用Flask-Limiter扩展自带Redis支持

Redis集成示例:

from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(
    app,
    key_func=get_remote_address,
    storage_uri="redis://localhost:6379"
)

@app.route('/api/fetch-news/<code>')
@limiter.limit("3 per hour")
def fetch_news_for_site(code):
    ...

2. 验证码体验

当前简单验证码仅用于开发测试,生产环境必须配置实际验证码服务。

3. CDN缓存

如果使用CDN确保/api/fetch-news/*路径不被缓存:

  • Cloudflare: Page Rules设置Cache Level: Bypass
  • 阿里云CDN: 配置缓存规则排除API路径

🎯 未来改进

短期 (1周内)

  • 配置Redis存储替换内存存储
  • 配置生产环境验证码服务reCAPTCHA或hCaptcha
  • 添加请求日志记录和监控
  • 优化前端错误提示UI

中期 (1个月)

  • 实现验证码UI组件
  • 添加管理后台查看API调用统计
  • 实现白名单机制管理员IP不限制
  • 添加用户友好的限流提示页面

长期 (3个月+)

  • 实现基于用户账号的限流(登录用户更高额度)
  • API调用成本统计和预警
  • 智能频率调整(基于历史行为)
  • 分布式限流支持

📞 技术支持

  • 开发者: Claude Code
  • 版本: v2.6.0
  • 发布日期: 2026-02-06

部署检查清单

  • 已安装Flask-Limiter依赖
  • 已更新app.py代码
  • 已更新detail_new.html模板
  • 已添加utils/rate_limiter.py
  • 已更新requirements.txt
  • 应用重启成功
  • 详情页不再自动加载新闻
  • 点击按钮可以加载新闻
  • 连续请求触发频率限制
  • 错误提示正常显示
  • (可选)已配置验证码服务
  • 可选已配置Redis存储

祝部署顺利v2.6将大幅降低API成本。 🎉

最后更新: 2026-02-06