CC攻击的肉鸡IP从哪来?秒拨与代理池特征

CC 攻击最迷惑人的地方在于:它看起来就是成千上万个「正常用户」在访问。本文用 9 个问答讲清 CC攻击 的 IP 到底从哪来、肉鸡与代理池与秒拨三者的区别、怎么从日志里认出 IP 池、为什么直接封 IP 会误伤真实用户,以及按指纹与 C 段聚合的实战限速配置。

Q:CC攻击的IP都是从哪来的?

攻击方手里的 IP 大致来自四类,成本从低到高:

  • 被入侵的主机,也就是肉鸡:个人电脑、被控制的服务器,以及摄像头、路由器这类物联网设备。
  • 代理池:公开或私有的 HTTP、SOCKS 代理被批量采集后打包出租。
  • 秒拨:用宽带账号反复拨号换取新 IP,一个账号一天能拿到成百上千个地址。
  • 云主机滥用:批量注册账号开通小规格云服务器,弹性扩缩的成本极低。

共同特点是:这些 IP 上一秒在打你,下一秒可能就在访问别的站点,甚至就是某个真实用户当天用过的地址。

Q:秒拨和普通代理池有什么区别?

  • 秒拨的 IP 是真实住宅宽带:归属地真实、信誉分高,多数 IP 信誉库不会把它标成恶意,这是最难防的一类。
  • 代理池多为数据中心 IP:公开代理大量被拉黑,拦截成本低、效果也差,所以攻击者更愿意花钱买秒拨。
  • 结论:秒拨比代理池难缠得多,因为它长得和真实用户几乎一模一样,单看 IP 地址根本分不出来。

Q:怎么从访问日志里认出这批IP?

核心是看分布形态,而不是看单个请求:

  • 单个 IP 请求量很小,几次到十几次就消失,然后再也不出现。
  • IP 数量极大且分散,但请求节奏、UA、Referer 高度一致。
  • UA 与 IP 归属地矛盾,例如中文 UA 配海外住宅 IP。
  • 只拉动态接口和搜索结果页,几乎不请求图片、CSS、JS。
# 1) 单位时间内不同 IP 数量,池子越大这个值越高
awk '{print $1}' access.log | sort -u | wc -l

# 2) 单 IP 请求次数分布:若绝大多数 IP 只出现 1 到 5 次,基本就是 IP 池
awk '{print $1}' access.log | sort | uniq -c | awk '{print $1}' | sort -n | uniq -c

# 3) 请求量与 UA 的对照
awk -F'"' '{print $6}' access.log | sort | uniq -c | sort -rn | head

把每秒不同 IP 数做成监控曲线,往往比每秒请求数更早暴露 IP 池攻击。

Q:怎么判断这些IP属于住宅宽带还是机房?

  • 查 ASN 归属:住宅宽带的 ASN 通常是电信、联通、移动这类运营商,机房 IP 的 ASN 多为云厂商与 IDC。
  • 查 IP 的注册信息与网段描述,看是否带有宽带、城域网、拨号这类字样。
  • 对比行为:住宅 IP 却在高频请求同一个接口,就是强信号,正常家庭用户不会这么干。
# 查看 IP 归属与网段描述
whois 203.0.113.7 | grep -iE 'netname|descr|org|country'

# 按 ASN 统计请求占比,找出异常集中的自治域
awk '{print $1}' access.log | sort -u | head -500 > ips.txt
while read -r ip; do whois "$ip" 2>/dev/null | grep -iE '^origin'; done < ips.txt \
  | sort | uniq -c | sort -rn | head

提醒一句:不要凭归属地直接封禁,移动网络的出口 IP 与几十万真实用户共享,一封就是一片。

Q:为什么直接封IP经常会翻车?

  • 秒拨 IP 会回流:拨号地址用完就还给运营商,第二天可能分配给真实用户,永久封禁等于给未来的用户埋雷。
  • NAT 出口背后是人海:企业专线、学校、移动网络,一个 IP 背后可能是成千上万个真实访客。
  • 封禁清单会失控:手工加的黑名单没人维护,几个月后就是一份误伤名单。

所以结论很明确:CC 的 IP 是耗材,封禁也要当耗材处理,用短时封禁而不是永久黑名单。

Q:Nginx层怎么针对IP池做限速?

# 第一层:单 IP 限速,做兜底
limit_req_zone $binary_remote_addr zone=ccip:10m rate=5r/s;
limit_req_status 429;
limit_conn_zone $binary_remote_addr zone=conn:10m;

# 第二层:按 UA 聚合。IP 会换,但 UA 与指纹往往不变
map $http_user_agent $ua_bucket {
    default              "";
    "~*python-requests"  "py";
    "~*Go-http-client"   "go";
    "~*curl/"            "curl";
}
map $ua_bucket $cc_key {
    ""       $binary_remote_addr;
    default  $ua_bucket;
}
limit_req_zone $cc_key zone=ccua:10m rate=3r/s;

server {
    limit_req  zone=ccip burst=10 nodelay;
    limit_req  zone=ccua burst=5  nodelay;
    limit_conn conn 20;
}
  • 按 UA 或指纹聚合是关键:IP 换了但 UA 没换时,这把令牌桶依然能卡住它。
  • 状态码统一用 429,不要用 403,也不要和真实故障常用的 503 混在一起。
  • 静态资源不要套用这套规则,避免拖慢真实用户的首屏。

Q:怎么按C段或ASN聚合封禁?

# 先统计请求量最高的 C 段
awk '{split($1,a,"."); print a[1]"."a[2]"."a[3]".0/24"}' access.log \
  | sort | uniq -c | sort -rn | head -20 > top24.txt

# ipset 建表,带 1 小时超时,避免永久误伤
ipset create cc24 hash:net timeout 3600 maxelem 200000
while read -r n c; do ipset add cc24 "$c"; done < top24.txt

# 只拦 Web 端口,保留管理通道
iptables -I INPUT -p tcp --dport 80 -m set --match-set cc24 src -j DROP
  • 只对整体行为异常的 C 段动手,单个 IP 异常交给上一层的限速处理。
  • 优先封聚合段加短超时,比逐个封 IP 有效得多,也更容易回滚。
  • 封禁前务必确认后端拿到了真实客户端 IP,否则在 CDN 回源场景会封掉回源节点。

Q:检测到IP池之后,还需要人工审核吗?

  • 不需要,三层自动处置已经够用:单 IP 限速、指纹聚合限速、段级短时封禁。
  • 再加一层人机验证,但只对可疑档触发,全站弹验证码会把真实用户一起赶走。
  • 监控上盯两个指标:每秒不同 IP 数、限速命中率。前者用来发现 IP 池,后者用来验证策略是否生效。
  • 定期复核封禁清单,确认没有把运营商 NAT 段、合作方接口一起封掉。

Q:还有什么补充建议?

  • 换掉封 IP 的思维:封 IP 只对固定 IP 的攻击者有效,对 IP 池几乎无效。
  • 升到行为与指纹维度:UA、TLS 指纹、Cookie、请求序列,这些比 IP 更难伪装。
  • 不追求清零:目标是让攻击成本上升、让体验损失最小,而不是把每一个可疑 IP 都封掉。
  • 源站藏好才是根本:把源站 IP 暴露给攻击方,再好的规则也会被绕过。
  • 别等被打才配:限速与聚合阈值平时就跑着,攻击来时才有基线可以对照。

一句话总结:CC 攻击的 IP 主要来自肉鸡、代理池、秒拨与云主机滥用,其中秒拨最难防;识别靠的是 IP 数量分布与 UA 一致性,处置靠单 IP 限速加指纹聚合加 C 段短时封禁,而不是一份越加越长的永久黑名单。