站点频繁被爬虫拖垮?基于香港服务器如何实现行为识别型反爬+限速机制?

站点频繁被爬虫拖垮?基于香港服务器如何实现行为识别型反爬+限速机制?

我维护着一个跨境电商平台,站点频繁遭遇大规模爬虫攻击——短时间内的高频请求直接拖垮了香港服务器前端的Nginx反向代理。传统的User-Agent或Referer黑名单策略早已失效,爬虫越来越“类人”,甚至模拟真实浏览器行为,连CDN的基础防护也被绕过。在这个背景下,我开始着手构建一套基于行为识别的反爬虫机制,并结合动态限速算法,有效减缓服务器压力,保障正常用户访问体验。

一、整体架构设计思路

目标是通过香港边缘服务器实施如下策略:

  • 实时检测异常请求行为,判定是否为爬虫;
  • 对可疑请求打标签,进入限速通道或直接拦截;
  • 使用Nginx + Lua动态响应机制,不依赖后端逻辑;
  • 所有行为数据写入Redis进行短期状态管理;
  • 配合WAF、JS挑战和IP reputation,实现联动防御。

架构流程如下:

[公网访问]
     |
 [香港CDN边缘] (WAF + JS挑战)
     |
 [Nginx + Lua行为识别] ──> Redis行为状态缓存
     |
   后端服务(API、页面)

二、关键模块实操部署

1. 基于Nginx + OpenResty行为识别

首先在香港服务器上部署OpenResty(Nginx + LuaJIT集成版本):

apt update
apt install -y openresty redis-server

编写Lua模块:behavior_detect.lua

local cjson = require "cjson.safe"
local redis = require "resty.redis"

-- 请求行为分析:UA合法性 + Referer + 访问频率
local function analyze_behavior()
    local headers = ngx.req.get_headers()
    local ua = headers["User-Agent"]
    local referer = headers["Referer"] or ""
    local ip = ngx.var.remote_addr
    local uri = ngx.var.uri

    -- 简单User-Agent合法性判断
    if not ua or ua == "" or ua:find("python") or ua:find("curl") then
        return "bad_ua"
    end

    -- Redis连接
    local red = redis:new()
    red:set_timeout(100)
    assert(red:connect("127.0.0.1", 6379))

    -- 请求频率检测(每10秒超过10次则标记)
    local key = "freq:" .. ip .. ":" .. uri
    local count = red:incr(key)
    if count == 1 then red:expire(key, 10) end

    if count > 10 then
        return "rate_limit"
    end

    return "ok"
end

local status = analyze_behavior()
if status == "bad_ua" or status == "rate_limit" then
    ngx.exit(429)
end

在OpenResty中引用此模块:

server {
    listen 80;
    server_name example.com;

    location / {
        access_by_lua_file /etc/openresty/lua/behavior_detect.lua;
        proxy_pass http://backend;
    }
}

2. Redis行为状态缓存结构设计

使用Redis作为行为状态存储,支持以下几类Key:

Key类型 示例 功能说明
freq:{ip}:{uri} freq:1.2.3.4:/api/goods 用于滑动时间窗内的访问计数
flag:badua:{ip} flag:badua:1.2.3.4 标记非法UA访问行为
jscheck:{ip} jscheck:1.2.3.4 是否通过JavaScript挑战验证

通过 EXPIRE 设置失效时间(例如10分钟),实现临时惩罚机制。

三、加入JavaScript挑战验证机制(可选)

对高频触发的IP,通过设置 jscheck:{ip}=false 标记后,跳转至挑战页:

location / {
    access_by_lua_block {
        local redis = require "resty.redis"
        local red = redis:new()
        red:connect("127.0.0.1", 6379)

        local ip = ngx.var.remote_addr
        local passed = red:get("jscheck:" .. ip)
        if passed == ngx.null then
            return ngx.redirect("/challenge")
        end
    }
    proxy_pass http://backend;
}

location = /challenge {
    default_type text/html;
    content_by_lua_block {
        ngx.say("<script>local s=Date.now(); while(Date.now()-s<500){}</script>")
        ngx.say("<script>location='/';</script>")
    }

    # 后端设置jscheck:{ip}=true
    log_by_lua_block {
        local redis = require "resty.redis"
        local red = redis:new()
        red:connect("127.0.0.1", 6379)
        red:setex("jscheck:" .. ngx.var.remote_addr, 600, "true")
    }
}

四、结合nginx rate-limiting模块进一步限速

http {
    limit_req_zone $binary_remote_addr zone=limit_per_ip:10m rate=5r/s;

    server {
        location /api/ {
            limit_req zone=limit_per_ip burst=10 nodelay;
            access_by_lua_file /etc/openresty/lua/behavior_detect.lua;
            proxy_pass http://api_backend;
        }
    }
}

五、与WAF/地理IP/ASN黑名单联动防御(增强策略)

建议对接以下辅助模块进一步强化识别精度:

  • MaxMind IP库判断是否来自IDC机房(爬虫伪装常见);
  • ASN识别(如AS37963、AS14061等云爬虫集群);
  • JS指纹绑定识别(如cookie+UA绑定、字体探针等)。

六、实战效果与运维经验

实施该套方案后,原本日常遭遇的爬虫请求从 每小时8万次压测 降到 1万次以内,关键API负载明显回落,正常用户访问延迟控制在50ms以内。

运维层面建议:

  • 每周复查Redis Key使用情况,避免泄露;
  • Lua逻辑建议抽象为模块,便于A/B测试;
  • 对接Zabbix或Prometheus观察被限频IP数、429返回数。

传统WAF已无法应对日益智能化的爬虫行为,必须将防御从静态黑名单转向动态行为识别与联动限速机制。基于香港边缘服务器部署此类防护,既贴近海外流量入口,又能有效分担后端压力,是我在实战中验证有效的一套技术解决方案。后续我也在尝试将机器学习模型引入Redis行为判断模块,进一步提高识别准确率。

未经允许不得转载:A5数据 » 站点频繁被爬虫拖垮?基于香港服务器如何实现行为识别型反爬+限速机制?

相关文章

contact