前言:
这篇文章的灵感来源于一次春运抢票失败的经历。
当时盯着12306的页面反复刷新,眼看着"有票"变成"无票",心里就在想:这背后到底有多少脚本在跟我抢?
于是干脆从攻击者的视角,把针对12306的整条攻击链路和对应的防御体系完整推演了一遍。
涉及的核心知识点包括:SYN泛洪攻击、高防IP、CC攻击、图形验证码、AI识别绕过、智能频率限制、请求队列机制以及候补购票机制。
全文为技术原理推演,不涉及任何真实攻击指导。个人主页:艺杯羹
1. SYN泛洪攻击:用半连接堵死12306
假设有人手写了一段攻击脚本,向12306的域名疯狂发送大量带有 SYN 标志位的 TCP 报文。
这些报文千篇一律,只请求建立连接,却永远不回复最后的 ACK 确认。
12306的服务器收到 SYN 后会分配资源等待握手完成,但这个等待永远不会结束。
半连接队列迅速被占满,正常旅客再也无法建立新的 TCP 连接。
这就是经典的 SYN Flood 泛洪攻击。
1.1. TCP三次握手与攻击原理
先回顾一下正常的 TCP 三次握手过程:
步骤 |
方向 |
报文标志 |
作用 |
第一次 |
客户端 → 服务器 |
SYN |
请求建立连接 |
第二次 |
服务器 → 客户端 |
SYN + ACK |
确认收到,等待回应 |
第三次 |
客户端 → 服务器 |
ACK |
连接正式建立 |
攻击者只发送第一步的 SYN,永远不完成第三步的 ACK。
服务器为每一个半连接分配内存和端口资源。
当半连接队列被塞满之后,服务器直接拒绝所有新的连接请求。
正常用户打开12306,页面转圈,加载不出来,根本原因就是这里。
1.2. 攻击脚本的核心逻辑(仅原理演示)
from scapy.all import IP, TCP, send import random target_ip = "203.0.113.50" # 虚构目标IP,仅作演示 for i in range(100000): # 伪造随机源IP地址,只发SYN,不回ACK src_ip = f"10.{random.randint(0,255)}.{random.randint(0,255)}.{random.randint(0,255)}" packet = IP(src=src_ip, dst=target_ip) / TCP(dport=443, flags="S") send(packet, verbose=0) print("SYN Flood 发送完毕")
风险提示:以上代码仅用于理解攻击原理。对任何真实目标执行此类操作均违反《中华人民共和国网络安全法》,属于刑事犯罪。
1.3. 攻击效果示意
图片说明:左侧为攻击者伪造海量SYN请求,中间为服务器半连接队列被占满,右侧为正常旅客的连接请求被拒绝。
2. 高防IP:流量根本没到12306的服务器
攻击者以为自己的流量全部砸向了12306的业务服务器。
但实际上,并没有。
12306的域名并没有直接解析到业务服务器的IP地址,而是解析到了一台 高防IP 服务器。
2.1. 高防IP的工作机制
所有进入的流量,都会先经过高防IP的流量清洗中心:
攻击者/正常用户 → 高防IP(流量清洗中心) → 12306业务服务器
清洗中心会对每一条流量进行分类判定:
流量类型 |
判定依据 |
处理方式 |
正常业务流量 |
完整三次握手、合法HTTP请求特征 |
放行至业务服务器 |
恶意攻击流量 |
大量SYN无ACK、伪造源IP、异常频率 |
直接丢弃或引入黑洞路由 |
攻击者发送的那批只带 SYN 标志位的报文,特征极其明显。
高防IP几乎在瞬间就把它们全部识别为恶意流量,清洗得干干净净。
2.2. 为什么SYN泛洪彻底失效
攻击者的流量从头到尾就没有触碰到12306真正的业务服务器。
高防IP就像一面防弹玻璃,外面砸得再猛,玻璃后面的服务器依然安然无恙。
这就是 高防IP 的核心价值:把攻击流量拦截在业务系统之外,让真正的服务器"隐身"。
图片说明:左侧为混合流量入口,中间为高防IP清洗层(恶意流量被红色拦截,正常流量绿色通过),右侧为12306业务服务器集群。
3. CC攻击:用13万真实用户身份伪装合法请求
直接发垃圾报文行不通了,攻击者换了思路。
既然高防IP能识别异常报文特征,那就让流量看起来完全合法。
3.1. 攻击路径转向第三方抢票平台
攻击者将目标转向了市面上的第三方抢票平台。
这些平台存在两个致命的安全问题:
第一,用户为了使用抢票服务,主动输入了12306的真实用户名和密码。
第二,这些平台自身的安全性往往非常低,用户名和密码甚至以明文形式存储在数据库里。
攻击者很快就从这些平台窃取到了 13万条 真实用户凭证。
3.2. 模拟真实用户并发登录
拿到凭证之后,攻击者编写自动化脚本,模拟这13万个"真实用户"在同一时刻并发登录12306。
import requests import threading credentials = load_stolen_data() # 加载13万条窃取的用户名密码 def fake_login(username, password): url = "https://kyfw.12306.cn/passport/web/login" payload = { "username": username, "password": password, "appid": "otn" } requests.post(url, json=payload) threads = [] for user, pwd in credentials: t = threading.Thread(target=fake_login, args=(user, pwd)) threads.append(t) t.start()
每一个请求都是完整的TCP三次握手。
每一个请求都携带合法的用户名和密码。
高防IP完全无法将这些请求与正常旅客的登录行为区分开来。
12306的服务器承受了巨大的并发压力。
这就是 CC攻击(Challenge Collapsar),专门针对应用层的资源消耗型攻击。
3.3. CC攻击与SYN Flood的本质区别
对比维度 |
SYN Flood |
CC攻击 |
攻击层级 |
传输层(L4) |
应用层(L7) |
报文特征 |
大量SYN,无ACK,特征明显 |
完整HTTP请求,看似合法 |
消耗资源 |
半连接队列、内存 |
CPU、数据库连接、业务逻辑 |
识别难度 |
低 |
极高(与正常请求混合) |
高防IP能否拦截 |
能,特征匹配即可 |
很难,需要更深层分析 |
图片说明:攻击者使用窃取的13万账号并发发起真实HTTP请求,突破传输层防御直接冲击应用层资源。
4. 图形验证码:给登录加一道"人肉关卡"
工程师一看,这样直接输入用户名密码就能登录的机制实在太不安全了。
于是在12306的登录界面加上了 图形验证码。
每次登录前,系统随机生成一张包含扭曲字符或图片选择的验证码。
用户必须正确识别并输入,才能继续登录流程。
自动化脚本"看不懂"图片内容,攻击瞬间失效。
4.1. 验证码防御的基本流程
用户请求登录 → 服务器生成验证码图片 → 用户肉眼识别并输入 → 服务器校验 → 通过则继续
关键在于:图片识别对脚本来说是一个高难度任务。
至少在当时的技术条件下,普通的自动化脚本根本搞不定。
4.2. AI识别绕过验证码
但攻击者很快想到了对策:用AI来识别验证码。
通过训练一个OCR模型,或者直接调用现成的打码平台API,脚本可以在毫秒级完成验证码内容的识别。
import ddddocr # 开源通用OCR识别库 ocr = ddddocr.DdddOcr(show_ad=False) def solve_captcha(image_bytes): """将验证码图片字节流传入,返回识别结果""" result = ocr.classification(image_bytes) return result
传统的图形验证码在AI面前几乎形同虚设。
防御方不得不持续升级验证码形式:滑块验证、点选文字、行为轨迹分析等更复杂的人机校验方案陆续登场。
这是一场"道高一尺,魔高一丈"的持续拉锯。
图片说明:传统静态字符/图形验证码被深度学习OCR识别模型快速破解绕过。
5. 智能频率限制与请求队列:从13万大军中揪出傀儡
即使攻击者绕过了验证码,工程师还有后手。
问题的核心变成了:如何从正常旅客中揪出这些被操控的傀儡账号?
5.1. 智能频率限制
系统开始监控每一个IP地址和设备指纹的请求频率。
一旦检测到单个访问源在单位时间内的请求次数超过异常阈值,立即触发封禁。
监控维度 |
正常旅客行为 |
触发封禁条件 |
单IP每分钟登录请求 |
1~3次 |
超过20次 |
单设备指纹每秒查询 |
1~2次 |
超过10次 |
单账号每小时操作次数 |
5~15次 |
超过100次 |
攻击者的13万个账号虽然分散,但每个账号的操作频率依然远超正常人类行为。
一个真实旅客不可能在一秒钟内刷新十次余票查询。
系统通过这些行为特征,逐步将傀儡账号识别并封禁。
5.2. 有序请求队列
另一个关键防御手段是引入 有序队列。
所有购票请求不再直接冲击业务逻辑层,而是先进入一个排队队列。
只有前面的请求被处理完毕,后面的请求才会被消费。
请求A → [队列位置1] → 正在处理... 请求B → [队列位置2] → 等待中... 请求C → [队列位置3] → 等待中... ... 请求N → [队列位置N] → 等待中...
这意味着即使攻击者制造了海量并发请求,服务器也不会被瞬间压垮。
队列就像一条单车道公路,不管后面堵了多少车,通过速度始终恒定。
服务器按照自己的节奏处理请求,攻击者制造再多并发也无济于事。
图片说明:高并发流量先经智能频控清洗异常行为,随后进入有序 FIFO 队列实现业务平滑削峰填谷。
6. 候补机制:从根源上让"抢"失去意义
攻击者发现,搞来十几万条真实用户数据,也对12306造成不了丝毫实质影响。
于是有人换了个思路:干脆不攻击了,直接开一个第三方抢票软件公司。
核心技术无非就是三板斧:不断更换IP + 模拟用户登录 + 后台高频刷票。
打着"优先抢票、加速包"的旗号,诱导大量旅客使用该平台。
随着用户越来越多,刷票频率越来越高,对12306系统造成的压力也越来越大。
6.1. 候补机制如何反制
12306的工程师推出了 候补购票机制。
核心规则非常简单:一旦有票放出或有人退票,多出来的票根本不会进入公共票池。
而是优先分配给在12306官方平台上登记了候补的用户。
退票 / 新增放票 ↓ 候补队列(优先级最高) ↓ 候补用户自动获得车票 ↓ 所有候补满足后仍有剩余 ↓ 剩余票源才进入公共票池
换句话说,第三方抢票软件刷得再快,也得等所有候补用户都满足之后,才有机会接触到剩余票源。
图片说明:退票/改签票源直达官方最高优先级候补队列,第三方刷票软件在无公共票池时彻底失效。
6.2. 第三方抢票软件的真实影响
用户认知 |
实际情况 |
"用抢票软件能更快抢到票" |
候补机制下,抢票软件无法优先获取票源 |
"买加速包能提高成功率" |
加速包本质是提高刷票频率,与候补优先级无关 |
"不用抢票软件就抢不到" |
官方候补通道才是最高优先级 |
"抢票软件帮我节省时间" |
高频刷票反而加重服务器负担,影响所有用户体验 |
在第三方软件上抢高铁票,不仅无法获得优先购票权,反而会成为变相攻击12306的帮凶。
7. 攻防演进全景总结
把整个攻防过程串起来,可以清晰地看到一条螺旋上升的演进链:
阶段 |
攻击手段 |
防御手段 |
攻击者的下一步 |
第一阶段 |
SYN泛洪攻击 |
高防IP流量清洗 |
转向应用层攻击 |
第二阶段 |
CC攻击(真实凭证) |
图形验证码 |
用AI识别绕过 |
第三阶段 |
AI + 自动化脚本 |
智能频率限制 |
分散频率规避检测 |
第四阶段 |
低频分布式请求 |
有序请求队列 |
转向商业化运营 |
第五阶段 |
第三方抢票平台 |
候补购票机制 |
攻击意义被彻底消解 |
图片说明:从 L4 SYN 泛洪到 L7 CC 攻击再到业务机制创新的五阶段螺旋攻防博弈。
每一次防御升级,都逼迫攻击者寻找新的突破口。
而每一次攻击进化,又催生出更精细的防御策略。
这就是网络安全领域最核心的规律:攻防永远是一场没有终点的螺旋博弈。
8. 写在最后
本文通过12306这个大家最熟悉的场景,完整推演了从SYN Flood到候补机制的攻防全链路。
这些知识点并不局限于铁路购票系统,它们广泛存在于电商秒杀、游戏登录、API接口保护等各类高并发场景中。
理解攻击者的思路,才能真正构建起有效的防御体系。
下次在12306上候补等票的时候,不妨想想这背后有多少层防御在默默守护着系统的稳定。
希望这篇文章能提供一个清晰的攻防思维框架