【Web安全】一次性搞懂 ReDOS 漏洞原理/检测/防御
【Web安全】一次性搞懂 XSS 漏洞原理/检测/防御
【Web安全】一次性搞懂 CSRF 漏洞原理/检测/防御
【Web安全】一次性搞懂 SSRF 漏洞原理/检测/防御
【Web安全】一次性搞懂越权漏洞原理/检测/防御
在Web应用的逻辑漏洞体系中,支付漏洞因其直接关联资金安全而成为攻击者的重点目标。这类漏洞并非依赖复杂的代码执行,而是利用支付流程中对关键参数(如金额、商品标识、订单状态)的校验缺陷,让攻击者以非正常方式完成支付(如低价购买高价商品、免费获取付费服务)。本文将深入解析支付漏洞的原理、典型场景及防御策略。
支付漏洞的核心是服务器对支付流程中关键参数的校验逻辑失效。正常支付流程中,商品金额、订单状态、支付方式等核心信息需经过严格的合法性与一致性校验;而存在漏洞时,系统可能直接信任客户端传递的参数、省略关键环节的验证,或对业务规则的边界判断模糊,导致攻击者可通过篡改参数等方式绕过正常支付逻辑,获取不当利益。
简单来说,就是“该算的钱算错了,该拦的支付放过了”。
支付漏洞的核心在于某一环节的校验缺失,典型链路如下:
price=100
的订单创建请求);price=100
改为price=1
);攻击链路可概括为:
攻击者 → 抓取订单生成请求 → 篡改支付相关参数 → 服务器未校验 → 以异常价格完成支付
支付流程中,订单生成阶段是抓包的关键时机。原因在于:
订单生成时,系统会将商品信息(ID、单价)、用户信息(会员等级、优惠券)、活动规则(折扣、满减)等整合为订单参数(如goods_id=101&price=299&discount=0.9&order_type=1
),这些参数直接决定后续支付金额和权益。
若此时未对参数进行服务器端固化,攻击者可通过 BurpSuite 工具抓取请求,篡改参数后重放,而后续的支付、订单确认等环节可能基于已篡改的订单信息处理,最终导致支付漏洞。
例如:用户购买“299元运动鞋”,生成订单的请求为POST /api/createOrder {goods_id:101, price:299}
,攻击者抓包后将price
改为9.9
,若服务器直接信任该参数,订单金额就会被改为9.9元,攻击者支付后即可获得商品。
支付漏洞的风险场景因业务逻辑不同而多样,以下为典型场景:
开发阶段,工程师常预留测试商品(如0元商品、内部折扣商品)用于功能测试,若测试完成后未删除或隐藏,且后端未限制访问权限,攻击者可能通过篡改商品ID访问这些隐藏商品。
典型案例:
某电商平台开发时预留测试商品goods_id=9999
(原价1000元,测试价0元),但未从商品列表中移除。攻击者通过抓包发现正常商品请求为goods_id=100-200
,尝试将goods_id
改为9999
后提交订单,服务器未校验该商品是否对普通用户可见,直接生成0元订单,攻击者支付0元即可获得商品。
付费功能(如会员服务、高级工具)的权限控制常依赖参数标识(如is_vip=0
代表非会员,service_type=free
代表免费服务),若服务器未校验参数与用户实际权限的一致性,攻击者可通过篡改参数绕过付费验证。
两种常见实现方式:
pay_status=0
代表未付费),攻击者通过查看JS源码发现后,在请求中改为pay_status=1
,服务器直接信任该参数,允许免费使用付费功能(如高清视频、高级模板)。vip_level=1
),后续将普通账号的请求参数改为vip_level=3
(高级会员),若服务器未校验用户实际会员等级,即可免费享受高级权益。订单类型参数(如order_type
)通常关联不同的价格规则(如0=普通订单
、1=会员折扣单
、2=活动特惠单
、-1=测试订单
),若服务器未限制order_type
的合法取值范围,攻击者篡改类型值可触发异常价格计算。
典型案例:
某平台order_type=0
时商品按原价计算(100元),order_type=-1
为内部测试订单(默认价格0元)。攻击者在生成订单时,将order_type=0
改为order_type=-1
,服务器未校验该类型是否允许普通用户使用,直接按0元生成订单,导致攻击者免费获取商品。
实际在挖掘该类型漏洞时,不要把 1 改成 0 发现没用就放弃,可以多尝试几个值。
系统常根据优惠券、会员等级自动计算最终折扣(如discount=0.8
代表8折、coupon_id=100
代表减50元),若服务器未校验折扣参数的合法性(如是否存在该优惠券、折扣是否符合规则),攻击者可篡改参数降低支付金额。
典型案例:
用户购买1000元商品,使用8折券后应付800元,请求参数为discount=0.8&coupon_id=100
。攻击者抓包后将discount
改为0.1
,并伪造coupon_id=999
(不存在的1000元优惠券),服务器未重新校验折扣合理性及优惠券有效性,直接计算金额为1000×0.1 - 1000 = -900元(甚至倒赚),导致支付逻辑异常。
goods_id
、price
、order_type
、discount
、coupon_id
)。price=100
→price=1
);9999
、0000
);0
→-1
、3
);discount=0.01
、coupon_id=9999
)。createOrder
)是否对关键参数进行服务器端重算:
goods_id
从数据库查询后计算,而非直接使用客户端price
;order_type
是否限制在合法枚举值内(如仅允许0、1、2
);coupon_id
是否存在、是否在有效期内)。支付漏洞的防御核心是服务器端“绝对掌控”关键参数,不依赖客户端传递的数据,具体措施如下:
goods_id
从数据库查询单价,结合商品数量、活动规则重新计算金额,忽略客户端传递的price
参数。order_type
、discount
等参数设置白名单(如order_type
仅允许0、1、2
),拒绝非法值。vip_level
必须从用户数据库查询,而非使用客户端值)。goods_id
、计算后金额、order_type
)进行加密签名(如使用安全的哈希算法(如SHA256)加盐),并将签名存入订单记录。goods_id
(如删除测试商品,或标记为“仅内部可见”并校验访问权限)。order_type
)。支付漏洞是逻辑漏洞中危害最直接的类型,其本质是服务器对支付流程中关键参数的校验缺失。从隐藏商品的非法访问到折扣参数的恶意篡改,攻击者的核心手段始终围绕“篡改订单生成阶段的参数”,而防御的关键在于让服务器成为参数的唯一决策者。
开发人员需牢记:客户端传递的任何支付相关参数都不可信,必须通过服务器端的重新计算、权限校验、签名验证来确保支付逻辑的完整性。只有将“不信任客户端”的原则贯穿支付流程设计,才能有效防范支付漏洞,保障资金安全。
本文是「Web安全基础」系列的第 6 篇,点击专栏导航查看全部系列内容。