说到航旅业API安全治理,我先讲个让我印象很深的场景:某航旅分销平台的搜索接口被脚本刷了一整夜,第二天早上一看,上游供应商按调用量计费的账单直接多了十几万。这事表面上是个成本事故,本质上却是API安全防线失守。航旅行业几乎所有关键业务都挂在API上——航班搜索、订单查询、支付回调、航变通知、在线值机、积分兑换,接口一旦失守,轻则账单暴涨,重则旅客数据被拖走。
这篇文章是我在落地航旅平台API安全治理时沉淀下来的一套思路,核心是四个技术环节:资产盘点、网关收口、数据防护、业务风控。四个环节叠加起来才叫纵深防御,单独拎出任何一个都扛不住真实攻击。适合航司技术、机票代理、航旅SaaS平台的接口负责人和安全工程师对照参考,也可以帮你盘点一下自己公司目前做到了第几环。
1. 航旅API的独特风险图谱:为什么单点防护注定不够
1.1 一张API调用链背后藏着多少攻击面
航旅业务的信息化程度在所有传统行业里算非常高的,但这也带来了一个尴尬:业务越依赖API,暴露面就越大。一个典型的机票分销链路是这样的:用户从OTA或代理人端发起查询→请求经过自有网关→转发到航司接口或GDS供应商→返回运价和舱位→用户下单→支付回调→出票→航变推送。这中间每一跳都可能是一个独立系统、独立团队、甚至独立供应商,接口协议五花八门,有REST、有SOAP/XML、有老式Socket报文,安全水位参差不齐。
我把航旅API最常见的攻击行为归纳成四类,它们在企业里普遍存在,但安全团队往往很难在同一个系统里看到全貌:
- 撞库与账号盗用。航旅账户绑定里程、积分、常旅客权益、历史行程,黑产拿到撞库成功的账号后,不只盗积分,还可能结合历史行程做精准诈骗。攻击面通常是登录接口、积分查询接口、常用乘机人列表接口。
- 爬虫抓取运价舱位。搜索引擎接口被高频调用,用于比价、动态定价、跟价。表面看只是流量变大,实际上干扰了收益管理,而且这些请求会继续向上游供应商透传,直接产生真金白银的计费成本。
- 水平越权遍历。订单详情、行程单、值机接口只校验“是否登录”却不校验“数据是否属于当前用户”,攻击者遍历订单号或PNR(旅客订座记录编号),就能拿到大量陌生人的姓名、证件号、手机号、行程轨迹。这是我见过最要命的漏洞类型,因为它不需要很高技术含量,只要会改参数。
- 自动化薅羊毛。优惠券领取、里程兑换、签到、抽奖类接口被脚本批量重放,营销预算被刷走,还污染活动数据。
1.2 “戴上网关就安全”是错觉,纵深防御本质是承认单点会失效
很多团队以为上了API网关、配了WAF就完成了安全治理,这个想法我特别理解,但也特别危险。网关能解决认证、限流、基础协议校验,但它不知道业务语义——比如一个合法登录用户查别人的订单,网关注册了么?能拦得住么?拦不住的。WAF擅长识别SQL注入、XSS这类攻击特征,但面对“用正确Token高频调用搜索接口”这种完全合法的请求,它基本没有判断能力。
纵深防御的核心出发点其实是承认现实:任何一个单点都可能被绕过,所以我们不做“一堵墙”,而是做多层防线。即使攻击者突破第一层,第二层还在等着他。我落地的四个环节,每一层解决一类问题:
- 第零层是认知问题,先知道自己有哪些API在跑,肉眼可见的和偷偷存在的都算——这是资产盘点。
- 第一层是入口问题,把所有API流量统一收口,做认证、限流、防重放——这是网关治理。
- 第二层是数据问题,敏感字段不能以明文形式到达不该到的地方——这是数据防护。
- 第三层是业务问题,识别“合法接口的非法用途”,在业务层面阻断撞库、爬虫、薅羊毛——这是业务风控。
四个环节环环相扣,没有哪一层可以被忽略。接下来我按落地顺序逐个拆解。
2. 环节一:先做资产盘点,把“看不见的API”找出来
2.1 资产盘点为什么比想象中难
做安全治理的团队常犯一个错误:一上来就买网关、配策略,结果网关只覆盖了公司官网上那几十个接口,真正被调用的接口却有一大半不在里面。航旅行业这种现象尤其严重,因为业务线多、系统建设时间长,很多接口是不同时期由不同团队甚至外包团队留下的。
我在一次排查中见过这样的情况:某个查航班动态的接口是五年前给某第三方渠道开的,早已不在任何文档里,但对方一直在调用,每天有几十万次请求,没有鉴权,没有限流。听起来不可思议,但这是真实存在的事。资产盘点的难点就在于——你没办法治理你不知道存在的东西。
2.2 用流量日志反查影子API的实操方法
我的做法是:不要先从文档入手,而是从事实流量入手。步骤如下:
第一,汇总所有入口流量日志。常见的入口日志来源有三个:Nginx/LVS/云SLB访问日志、API网关的调用记录、防火墙或云平台的流量镜像。把它们统一收集到一个查询平台里,按域名+路径聚合。
第二,生成“事实接口清单”。对日志里的URL路径做归一化处理:去掉动态参数部分(比如/order/12345归为/order/{id}),替换常见路径分隔符,然后按接口路径聚合调用量。这一步能得到一份真正在线上运行的接口集合,而不是理论上的接口列表。
第三,与网关正式发布清单比对。差异项就是疑似影子API。对这些接口逐个确认:是谁在调用、调用方是否还是签约合作方、接口是否还有人维护、有没有鉴权。
第四,拉上开发团队一起认领。这一步千万别省,安全团队自己推断容易出错,一定要把清单发给各业务线开发,逐条确认或删除。这个环节会得罪人,但必须做——你保护的是他们写出来的数据。
2.3 资产台账不是一次性交付物,而是动态地图
完成盘点后,我强烈建议把结果沉淀成一份持续维护的资产台账,而不是一个做完就没人看的Excel。字段至少包括这些:
- 接口路径与请求方法(GET/POST/PUT/DELETE)
- 所属业务域(搜索、订单、支付、积分、会员等)
- 接口Owner(团队+具体负责人)
- 调用方类型(内部服务、自研App、Web前端、第三方合作伙伴)
- 当前认证方式(无、AppKey、Token、mTLS等)
- 涉及的数据标签(是否包含PII、证件号、行程信息)
- 风险等级(高/中/低,由数据敏感度和暴露面共同决定)
- 上线/下线状态
这份台账是后面三层策略的“地图”。网关策略、脱敏规则、风控阈值全部要基于这张地图去配置,否则就是盲配。后续每次新接口发布,强制要求必须在网关注册并填写Owner,每两周自动比对一次入口日志和台账清单,发现未登记的接口自动告警。做到这一步,治理的地基才算打好。
3. 环节二:网关层统一收口,认证、限流、防重放一次做对
3.1 不是所有接口都该用同一种认证方式
网关层最容易犯的错就是“一刀切”:所有接口都套同一个认证方案。现实是航旅API有完全不同的调用场景,必须分级对待。我落地时把认证分为四类:
| 调用场景 | 推荐方案 | 关键点 |
|---|---|---|
| 内部服务间调用 | mTLS双向证书或独立服务账号 | 不暴露到公网,内网单独网络策略 |
| 合作伙伴/供应商调用 | OAuth2 client credentials + AppKey | 每个伙伴独立Key,便于审计和按合作方限流 |
| C端用户调用 | OAuth2授权码模式 + JWT | Token内嵌用户ID和会话上下文,网关验签 |
| 高风险写操作(改绑手机、兑换、出票) | 在JWT基础上加二次校验 | 短信验证码/支付密码,双因子兜底 |
为什么这么设计?核心逻辑是:把“身份可信度”和“操作风险等级”匹配起来。查询航班是低风险,读自己的订单是中风险,出票/退款/改签是高风险,它们不该站在同一个安全水位上。C端接口只验Token不够,还要验Token里的用户上下文,网关解析完Token后把用户身份传给下游业务服务,这样后续的数据权限校验才有依据。
3.2 限流阈值不能拍脑袋,要按业务和成本双重维度设计
限流是所有安全治理里最容易误伤正常业务的环节。航旅场景有个典型特征:高峰期流量波动极大,大促、节假日、航变批量通知的时候,瞬时流量可能是平日的几十倍。限流阈值拍脑袋设低了,就把真实用户挡在外面。
我的建议是限流至少要按三个维度组合:
- AppKey维度:每个合作伙伴/渠道单独配额。某个分销商调用量超出约定时,直接排队或降级。
- 用户维度:单用户每秒/每分钟的调用次数。防止单个账号被脚本控制后刷接口。
- IP维度:仅作为临时兜底,不作为主要手段,因为差旅公司/企业用户经常整个公司共享几个出口IP,按IP上限容易误伤一片。
算法上,我习惯“令牌桶+滑动窗口”组合。令牌桶用来平滑突发流量,滑动窗口用来识别短时间高频异常。搜索类只读接口限流阈值可以放宽,但订单创建、支付回调这类写操作不仅阈值要低,还要做幂等控制,防止客户端重试导致重复下单。
还有一个航旅特有的维度:成本配额。很多航旅接口的上游是按调用次数向GDS或航司付费的,一次恶意爬虫刷的可能就是几十万的成本。所以我会在网关里给每个合作伙伴设置“日成本上限”,达到上限后,后续请求自动走缓存或者降级提示,宁可损失一点体验,也不能让一条脚本把预算刷爆。
3.3 防重放别只做一半,timestamp+nonce的落地细节
重放攻击在航旅API里非常常见——攻击者抓包拿到一个合法的下单请求,原样重放N次,就可能产生大量恶意订单。防重放的标准做法是timestamp+nonce+签名:
客户端在请求头里带三个值:时间戳timestamp、随机数nonce、以及用共享密钥对请求内容计算的签名。服务端先校验timestamp是否在允许的时间窗口内,然后查redis里有没有这个nonce——如果存在,说明是重放,拒绝;如果不存在,就写入redis并设置TTL。
落地时有几个坑我必须提一下:
时间窗口别设太死。移动端弱网情况下请求会有重试,客户端时钟和服务端也可能有偏差。我通常设±5分钟,既能防大部分重放,又不会造成大量正常请求误杀。
nonce存储必须有TTL。如果不设过期时间,redis内存会被撑爆。设成跟时间窗口一样长即可。
老客户端的兼容问题。我给某个App做防重放时,发现老版本客户端根本没有签名能力,如果强行全量开启,所有老用户都会挂掉。后来用了一个过渡方案:老版本客户端走IP白名单+简化校验,新版本强制签名,App灰度升级完成后才彻底关掉旧通道。这类问题不在技术本身,而在上线节奏管理。
4. 环节三:数据层防护,让敏感字段到不了不该去的地方
4.1 航旅数据里的“核心敏感字段”清单
很多团队做数据安全时有个误区:把所有字段都加密、所有字段都脱敏,结果业务跑不动了,最后只好悄悄放开。正确做法是先分级,再分场景处理。
航旅API涉及的数据我分成三个级别:
- 一级(高敏):身份证号、护照号、手机号、邮箱、完整姓名、银行卡信息、常旅客卡号。这些字段一旦泄露就能定位到具体个人,必须重点防护。
- 二级(中敏):历史行程、常用乘机人列表、同行人关系、座位偏好、酒店偏好。这类数据单独看可能不算特别敏感,但组合起来能刻画一个人的完整行为画像,也是黑产用于精准诈骗的原料。
- 三级(商业敏感):运价、舱位库存规则、协议客户价格、渠道佣金比例。这类不涉及个人隐私,但涉及商业竞争力,同样不能对外泄露。
4.2 动态脱敏:存储保留全量,返回按场景变形
脱敏的目标不是把数据库里的数据改掉——那叫静态脱敏,通常用于测试环境。生产环境要的是动态脱敏:数据库存全量真实数据,接口返回值按调用方身份和场景实时处理。
我落地过两种动态脱敏方式:
第一种是网关层脱敏。在API网关的响应链路里加一个脱敏插件,根据接口路径和字段路径配置规则,比如返回体里passenger.idNo这个字段统一做中间掩码。优点是对下游业务代码零侵入,适合所有对外部渠道开放的接口。缺点是只适用于JSON等结构化返回,且规则配置多了以后维护成本上升。
第二种是开发框架注解。在Java服务里自定义一个@Desensitize注解,配合Jackson序列化器,在字段序列化时自动按规则变形。优点是开发人员几乎无感,适合内部系统自用接口;缺点是需要各业务服务配合改造。
两种方式可以混合用:对外渠道走网关脱敏,内部系统之间用注解脱敏,核心高敏字段按需全量。脱敏算法上,身份证保留前1后2加掩码、手机号保留前3后4、邮箱保留前缀首字符和域名,这些规则要全团队统一,否则同一个数据在不同接口里脱敏格式不一样,下游没法做关联。
还有两个容易被忽略的点,我踩过之后印象很深。一是日志里不能有明文敏感字段,很多接口虽然返回脱敏了,但应用日志把完整请求报文打了出来,这等于脱了个寂寞。二是测试环境和备份库的静态数据必须脱敏,生产环境防护得再好,测试库被拖走一样是安全事故。
4.3 越权访问的终局解法:把数据归属校验做成框架级能力
水平越权是航旅API最严重的业务逻辑漏洞。很多系统做了认证(authentication),拿到了用户是谁,但完全没做授权(authorization),没有校验这个用户是否有权限看这条数据。
修越权最直接有效的方法是行级权限过滤。拿订单查询接口举例,原来的SQL可能是:
SELECT * FROM orders WHERE order_no = #{orderNo}加固后至少改成:
SELECT * FROM orders WHERE order_no = #{orderNo} AND (buyer_id = #{currentUserId} OR EXISTS ( SELECT 1 FROM order_passengers WHERE order_id = orders.id AND passenger_phone = #{currentUserPhone} ))把“当前登录用户”强制塞进查询条件,这样即使攻击者遍历订单号,也查不到不属于自己的数据。但问题在于,如果每个接口都靠开发人员自觉改SQL,迟早有遗漏。更稳妥的做法是做一个对象级授权中间件:在业务代码进入前,统一拦截“当前访问的资源Owner是否等于当前用户或共享组成员”。这个中间件需要业务以声明式方式告诉框架“这条数据属于谁”,但收益非常大——一旦做成了,整个公司所有接口都能共用这套能力,而不是靠人肉修SQL。
5. 环节四:业务风控实时接管,拦下“合法接口的非法用途”
5.1 WAF和网关都拦不住“长得像正常请求”的攻击
到这里已经做了三层防护,但我仍然不建议收工。因为撞库、爬虫、薅羊毛这些行为有一个共同特点:它们使用的请求本身完全合法——正确的Token、正确的参数格式、正确的接口路径,WAF规则看得懂SQL注入,看不懂“这个账号一分钟查了30条不同航线”意味着什么。
这时候就需要业务风控引擎。它和网关的区别在于:网关看的是“请求是否合规”,风控看的是“行为是否合理”。
5.2 规则引擎的落地样例:从特征到处置
风控引擎的输入是实时请求上下文:账号ID、IP、设备指纹、调用频率、接口路径、参数组合、时间分布。输出是处置动作:放行、验码、限速、拒绝、人工审核。
我不建议一上来就上机器学习模型,航旅业务规则性强,规则引擎起步更快、可解释性更强、出问题也好排查。下面是我在项目里沉淀过的几条典型规则,供参考:
| 风险场景 | 特征信号 | 处置动作 |
|---|---|---|
| 撞库攻击 | 同IP下多账号登录失败率高于70% | 滑块验证、临时封禁IP |
| 运价爬虫 | 短时间高频搜索同一航线不同日期低价舱位 | 降级响应优先级、触发验证码 |
| 薅羊毛 | 同设备/手机号高频领取优惠券且历史积分异常增长 | 自动驳回、转人工审核 |
| 越权试探 | 请求路径中订单号/PNR连续变化且大量404 | 拉黑会话、告警到安全团队 |
| 批量航变查询 | 单账号每分钟查询航班动态超过阈值 | 限流降级,返回缓存数据 |
规则的阈值不要拍脑袋定,要从历史日志里统计正常用户行为的P95/P99分位值,再往上留出安全边际。比如正常用户一天最多查30次航班动态,那阈值可以设在50次,降低误报的同时又能覆盖绝大多数自动化脚本。
5.3 用TraceId把四层串起来:安全溯源不是看单点日志
纵深防御有个隐含前提:每一层都要能联动。联动靠什么?靠全链路追踪。
我的做法是在网关入口生成一个TraceId,通过HTTP Header透传给下游所有服务,所有日志都以TraceId为索引。这样当风控引擎标记了一个攻击请求,安全团队可以顺着TraceId把这条请求的完整链路拉出来:从哪个IP进来→网关校验结果→到达哪个业务服务→触发了什么规则→返回了什么数据。排查一次攻击从小时级变成分钟级。
更进一步,把确认的攻击者特征(IP、设备指纹、账号、风险标签)写回一个威胁情报库,网关和风控引擎实时订阅。某IP一旦被识别为爬虫,全网的接口都会对他强化验证。这就是“一处识别、全局联动”。
6. 四层联动验证与实战中的避坑记录
6.1 老接口兼容问题:新治理方案差点把存量业务打死
前面提过老客户端签名兼容的问题,这里再补一个同类事件。我们曾在网关层强制所有接口必须带AppKey,结果上线当天,几个合作了七八年的供应商全部报错——他们当年对接时根本没有什么AppKey概念,用的是裸URL带参数。强行切过去意味着所有第三方都要改代码,周期至少两个月。
后来处理方式是:给老合作伙伴开“过渡白名单”,保留无鉴权调用通道,但加IP白名单绑定和调用量硬上限,同时书面通知对方限期完成升级。这个案例给我的教训是:安全治理是长期工程,节奏比完美更重要。宁可先让老接口带着“临时限制”跑着,也不能一上线就把业务全断掉。
6.2 限流阈值调整引发的误伤事故
有一次大促前,运营同学怕被脚本刷爆,让我把搜索接口的用户维限流阈值从每秒5次调低到每秒2次。结果大促当天上午十点,大量正常用户被429拒绝,投诉直接炸了。事后复盘发现两个问题:一是阈值没有参考历史峰值,只凭感觉调;二是没有做上线前的真实流量压测。
现在的做法是:任何限流阈值调整必须走“历史流量P99分析+全链路压测+灰度发布”三步流程,且至少留出20%以上波动空间。另外加了弹性限流逻辑——正常流量下阈值可以放宽,检测到异常突发时才动态收紧,避免与正常用户抢时间窗口。
6.3 告警疲劳:几百条告警等于没有告警
安全治理上线后最尴尬的场面不是没告警,而是告警太多没人看。我们曾经把所有风控事件全部推到告警群,一天几百条,三天后群就没人说话了。
后来做了一个告警分级体系:
- P0:已确认攻击行为或严重的越权尝试,风控引擎自动阻断并即时通知安全值班;
- P1:疑似攻击行为,进入工单系统,当天处理;
- P2:行为可疑但未构成明确威胁,只做记录,用于后续规则优化和画像沉淀。
同时每两周review一次规则命中率,把连续两周零命中的规则下掉,把明显误报的规则调参。告警系统必须让人看,否则投入产出比就是负数。
6.4 每个季度做一次“红队自测”,验证四层是否真的联动
最后分享一个我特别推荐的验证方法——季度红队自测。让安全团队扮演攻击者,专门打贯通案例,验证的不只是单点防护,而是四层之间是否真的联动。下面是我常用的自测清单:
| 自测项目 | 预期结果 |
|---|---|
| 构造一个未登记的测试接口,看能否被流量比对发现 | 资产盘点环节应发现并告警 |
| 绕过AppKey直接请求内网IP | 网关/网络策略应拒绝 |
| 修改接口参数中的订单号,尝试查他人订单 | 数据授权中间件应拦截 |
| 重放一个抓包拿到的下单请求 | 防重放机制应拒绝 |
| 高频调用搜索接口模拟爬虫 | 网关限流和风控引擎都应触发 |
| 检查高敏字段的接口返回值 | 应只返回脱敏后的数据 |
每次演练结果都形成报告,修复后复测。几轮下来,四层防线之间有没有洞、哪里衔接不畅,都会暴露得非常清楚。
我在实际项目里最大的体会是:如果非要说四个环节里哪个最该先做,我会选资产盘点。网关再强,拦不住一个你压根不知道存在的接口,也是白搭;数据防护规则再完整,不知道哪个接口在返回敏感字段,也是空转。治理的复杂度不会因为跳过某一步而消失,只会累积到某次事故里集中爆发。先摸清家底,再谈纵深防御,这条顺序不要走反。