CC攻击打在高频搜索接口上,和打普通页面的防御逻辑完全不同。搜索接口每次请求都要走数据库查询、分词、排序、缓存穿透判断,单次请求的资源消耗可能是静态页面的几十倍。攻击者不需要很大的流量,只要用较低的请求速率持续打在搜索接口上,就能让后端CPU和数据库连接数迅速耗尽。所以防护的重点不是单纯看QPS高低,而是识别“高频、同质、低价值”的请求特征,并在靠近业务层的位置做精细化限制。
先明确一个核心判断:搜索接口的CC攻击,绝大多数不是泛洪型,而是资源耗尽型。攻击者会构造大量不同的关键词,绕过缓存,迫使后端每次都执行真实查询。这种攻击的请求量可能只有每秒几十到几百,但足以拖垮一个没有做专门防护的搜索服务。因此,防护策略必须围绕“降低单次请求成本”和“识别异常访问模式”两条线同时展开。
第一层:接口层的速率限制要按用户身份分级搜索接口的限速不能一刀切。未登录用户、普通登录用户、付费会员、内部调用方,应该设置完全不同的阈值。未登录用户通常只给最低的查询配额,例如单IP每分钟不超过20次搜索,超过后返回429并附带Retry-After头。登录用户按用户ID限速,而不是按IP,因为攻击者可能持有大量账号或者伪造登录态。对于付费会员或高价值用户,可以适当放宽,但也要设置绝对上限,防止账号被盗用后参与攻击。
实现上建议用Redis做计数,key的设计要包含时间窗口和身份标识。例如未登录用户用IP,登录用户用UID,内部服务用AppID。计数采用滑动窗口而不是固定窗口,避免窗口边界被利用。固定窗口在每分钟的第59秒和第1秒各发一批请求,实际两秒内可能发出两倍的配额。滑动窗口可以用Redis的ZSET实现,每个请求记录一个时间戳,查询时移除窗口外的记录再计数。如果请求量极大,可以退化为固定窗口加随机抖动,减少Redis压力。
第二层:识别搜索行为的异常模式,而不只是看频率单纯限速会误伤正常用户,尤其是电商或内容平台,用户连续搜索几个商品关键词是常见行为。真正有效的防护要分析请求内容的特征。攻击者为了穿透缓存,通常会使用随机字符串、无意义组合、超长关键词或者大量同义词变体。正常用户的搜索词长度分布相对集中,通常在两到十五个字符之间,且词频分布符合幂律。攻击流量中的搜索词往往长度异常、字符分布均匀、重复率极低。
可以在网关层或搜索服务前置一层轻量级分析模块,对每个搜索请求提取特征:关键词长度、是否包含常见词、是否命中历史高频词库、同一用户短时间内搜索词的编辑距离、搜索词中特殊字符占比等。将这些特征输入一个简单的规则引擎或轻量模型,对异常请求直接拦截或降级处理。例如,单用户30秒内搜索词两两之间的编辑距离都大于5,且没有一个词出现在近7天高频词表中,基本可以判定为恶意探测。
第三层:缓存策略必须针对搜索场景做穿透保护搜索接口的缓存不能只依赖简单的key-value命中。攻击者使用随机关键词,缓存命中率会趋近于零,所有请求都穿透到后端。这时需要在缓存层增加“空结果缓存”和“热点词预判”。对于查询结果为空的关键词,也缓存一个短TTL的空结果,比如30秒到2分钟。攻击者即使使用随机词,只要重复出现,第二次就能命中空结果缓存,不再消耗数据库资源。
更进一步的方案是布隆过滤器前置判断。将历史存在结果的关键词放入布隆过滤器,请求进来时先判断关键词是否可能存在结果。如果布隆过滤器判断不存在,直接返回空结果,不查询数据库。布隆过滤器会有误判率,但可以通过调整位数组大小和哈希函数数量控制在可接受范围内。这个方案对随机字符串攻击非常有效,因为随机词几乎不可能在布隆过滤器中命中。
第四层:搜索接口的降级与熔断要独立配置搜索服务往往依赖多个下游,包括搜索引擎集群、数据库、推荐服务等。CC攻击打过来时,如果搜索接口的熔断阈值和普通接口一样,可能会导致整个服务雪崩。搜索接口应该配置独立的降级策略,当后端查询延迟超过阈值或错误率上升时,优先返回降级结果,例如热门搜索词的结果、默认推荐内容或简化的搜索结果,而不是直接报错。
降级逻辑要提前设计好,不能等攻击来了再临时处理。例如,当搜索集群的P99延迟超过800毫秒时,自动切换为“简单匹配模式”,只做数据库的LIKE查询或直接返回预设的热门结果集。当数据库连接池占用超过85%时,停止接受新的复杂查询请求,只处理白名单内的关键词。这些阈值需要在压测中反复验证,确保降级本身不会引入新的性能瓶颈。
第五层:在边缘层过滤明显的自动化流量很多CC攻击工具会使用固定的User-Agent、缺少完整的浏览器指纹、或者请求头顺序异常。在CDN或负载均衡层可以配置规则,对缺失Referer、User-Agent为默认库字符串、请求头顺序与真实浏览器不一致的请求直接拦截。搜索接口的请求通常来自前端页面,Referer应该包含站内搜索页的地址。如果Referer为空或者来自异常域名,可以直接拒绝。
同时可以启用JavaScript挑战或Cookie校验。对于未携带有效会话Cookie的搜索请求,先返回一个需要执行JavaScript的页面,验证通过后再放行。这会增加攻击者的成本,因为大多数CC攻击脚本不执行JavaScript。但要注意,这个方案对移动端App的API请求不适用,需要区分来源。对于App请求,可以校验签名和时间戳,要求客户端携带动态生成的签名参数,签名算法中加入时间窗口和密钥,攻击者难以伪造。
第六层:后端查询本身要做资源隔离和超时控制即使前面的防护都做了,仍然可能有漏网之鱼。搜索服务内部必须对单次查询的资源消耗做硬性限制。例如,限制单次查询最多扫描的文档数、最大返回结果数、最长查询执行时间。搜索引擎如Elasticsearch可以配置max_result_window、timeout参数,数据库查询要设置statement timeout。对于超时的查询,主动终止并记录日志,而不是让线程一直等待。
线程池隔离也很关键。搜索接口的请求处理线程池要与普通业务接口分开,避免搜索接口被攻击时占满所有线程,影响登录、下单等核心功能。可以为搜索接口单独分配一个线程池,设置较小的队列长度,当队列满时直接拒绝新请求,快速失败。这样即使搜索服务被打满,也不会拖垮整个应用。
第七层:日志与实时监控要能快速定位攻击源防护措施上线后,必须能看到效果。搜索接口的日志要记录每个请求的用户标识、IP、关键词、查询耗时、是否命中缓存、返回结果数量。这些日志可以异步写入,避免影响请求性能。通过实时分析日志,可以发现攻击流量的特征变化。攻击者会不断调整策略,比如从随机词改为字典词,从单IP改为代理池。监控系统要能按关键词长度分布、请求间隔分布、错误率趋势等维度聚合,快速识别新的攻击模式。
建议对搜索接口设置独立的告警规则。当搜索QPS突增超过基线三倍、空结果率突然升高、平均查询耗时大幅上升时,立即触发告警。告警信息中要包含Top IP、Top关键词、Top用户ID,方便运维人员第一时间封禁或调整策略。
第八层:长期策略是建立搜索接口的信任体系单纯的限速和拦截无法彻底解决问题,因为攻击者可以不断更换IP和账号。更持久的方案是建立一套信任评分机制。每个用户或IP都有一个动态的信任分,正常搜索行为加分,异常行为减分。信任分低的请求会被要求完成验证码、降低查询优先级或直接拒绝。信任分可以基于历史行为、设备指纹、账号注册时间、消费记录等多个维度计算。
例如,一个新注册的账号在五分钟内发起了50次搜索,且搜索词之间没有明显关联,信任分就会快速下降。当信任分低于阈值时,该账号的搜索请求会被要求先完成图形验证码。对于持续低信任分的账号,可以限制其搜索功能,只允许浏览推荐内容。这种机制比单纯的频率限制更灵活,也更难被绕过。
防护CC攻击限制高频搜索接口请求,本质上是在可用性和安全性之间找平衡。限得太严,正常用户体验受损;限得太松,攻击者有机可乘。真正有效的方案一定是多层组合,从边缘层的流量清洗,到接口层的身份限速,再到业务层的行为分析和后端资源隔离,每一层都承担不同的职责。同时要建立快速响应机制,攻击发生时能第一时间调整策略,而不是依赖一套静态规则。搜索接口的防护是一个持续对抗的过程,攻击手法在变,防护策略也要跟着变。
