如何防止客户端向PHP服务端提交支付请求前篡改商品价格
防价格篡改解决方案(PHP服务端)
核心原则:绝对不要信任任何前端提交的金额类数据,所有金额计算、校验逻辑必须在服务端完成,具体落地方案如下:
- 移除前端金额透传逻辑
不要将总价存放在hidden input中传递,前端结算页仅需要提交商品ID、购买数量、支付渠道标识三个核心参数即可,禁止透传任何价格、总金额类字段。 - 服务端统一计算应收金额
收到前端结算请求后,PHP服务端根据商品ID查询数据库中存储的商品官方单价,结合购买数量、运费规则、已领取的优惠抵扣规则,自行计算出真实的应收总金额,该金额为后续传递给移动支付API的唯一有效数值,全程忽略前端传递的任何价格相关参数。 - 特殊场景下加签名双重校验
如果你对接的移动支付API流程强制要求前端携带总金额参数提交,可增加签名校验机制做兜底:- 服务端渲染结算页时,先计算出真实应收金额,将
商品ID+购买数量+应收金额+服务端私有秘钥拼接后做哈希运算得到签名值,将签名值存入前端隐藏域和订单数据中 - 前端提交支付请求时将签名值一同传回服务端,服务端按同样规则重新计算签名,和传回的签名做对比,不一致直接拒绝请求
对应PHP示例代码:
// 结算页生成签名逻辑 $server_secret = '你自行定义的私有秘钥,存在服务端配置文件中,不可泄露'; $goods_id = 123; // 从数据库读取的商品ID $buy_num = 1; // 用户选择的购买数量 $real_total = 200; // 服务端计算得到的真实应收金额 $sign = md5($goods_id . $buy_num . $real_total . $server_secret); // 将$sign存入前端隐藏域随其他参数一同提交// 支付请求接收后的校验逻辑 $recv_goods_id = intval($_POST['goods_id']); $recv_buy_num = intval($_POST['buy_num']); $recv_total = floatval($_POST['total_amount']); $recv_sign = trim($_POST['sign']); $server_secret = '你自行定义的私有秘钥'; $calc_sign = md5($recv_goods_id . $recv_buy_num . $recv_total . $server_secret); if($calc_sign !== $recv_sign){ die("参数非法,请求已拒绝"); } // 签名校验通过后,必须再查数据库重新计算一次金额,和$recv_total做二次对比,避免签名规则被破解 - 服务端渲染结算页时,先计算出真实应收金额,将
- 支付回调二次校验
收到支付渠道的支付成功回调通知后,先查询对应订单的应收金额,和回调接口返回的实际支付金额做对比,只有金额完全一致、订单状态为待支付的情况下,才将订单标记为支付成功,避免回调数据被篡改。
内容的提问来源于stack exchange,提问作者Adam K
相关产品推荐
相关产品推荐

