PAYATHON 2026

支付宝付款后的异步通知能否携带付款者IP?

支付阿杰

结论

支付宝付款完成后的标准异步通知通常不包含付款者 IP,也没有通用的通知参数可用于获取该信息。buyer_id、buyer_logon_id 等字段记录的是付款方身份信息,不是 IP 地址。

部分接口会要求商户在创建交易时提交 client_ip 等字段。这类字段通常由商户采集并作为请求参数传给支付宝,并不表示支付宝会在异步通知中返回付款者的真实 IP。实际字段应以对应产品和接口版本的官方参数文档为准。

原因

异步通知用于向商户反馈交易状态、金额等结果,常见字段有:

  • out_trade_no:商户订单号
  • trade_no:支付宝交易号
  • trade_status:交易状态
  • total_amount:订单金额
  • buyer_id:买家支付宝用户 ID
  • buyer_logon_id:买家支付宝账号的脱敏信息

付款者 IP 不属于标准交易结果字段。即使用户通过浏览器或 App 完成付款,支付宝也不会在常规异步通知中直接向商户提供用户的网络地址。

解决方法

如果业务需要记录用户发起付款时的 IP,可以在商户自己的支付入口采集,并与 out_trade_no 一起保存:

  1. 用户在商户页面提交订单。
  2. 商户服务器获取当前请求的客户端 IP。
  3. 创建唯一的 out_trade_no。
  4. 将 IP、订单号和创建时间写入订单记录。
  5. 收到支付宝异步通知后,通过 out_trade_no 查询原订单。
  6. 完成验签,并核对金额和商户身份后更新订单状态。

这里保存的是用户访问商户支付接口时的 IP,不一定是用户最终在支付宝完成付款时使用的 IP。

PHP 示例

<?php

function getClientIp(array $trustedProxies = []): string
{
    $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '';

    // 只有请求确实来自可信反向代理时,才解析代理传递的地址。
    if (in_array($remoteAddr, $trustedProxies, true)) {
        $forwardedFor = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';

        if ($forwardedFor !== '') {
            $ips = array_map('trim', explode(',', $forwardedFor));

            foreach ($ips as $ip) {
                if (filter_var($ip, FILTER_VALIDATE_IP) !== false) {
                    return $ip;
                }
            }
        }
    }

    return filter_var($remoteAddr, FILTER_VALIDATE_IP) !== false
        ? $remoteAddr
        : '';
}

$outTradeNo = generateOutTradeNo();
$clientIp = getClientIp(['10.0.0.10']); // 替换为实际可信代理地址

saveOrder([
    'out_trade_no' => $outTradeNo,
    'client_ip'    => $clientIp,
    'status'       => 'pending',
]);

// 随后使用 $outTradeNo 创建支付宝交易。

处理异步通知时,通过订单号关联此前保存的 IP:

<?php

$notifyData = $_POST;

// verifyAlipaySignature() 应使用支付宝公钥和对应签名算法验签。
if (!verifyAlipaySignature($notifyData)) {
    http_response_code(400);
    exit('failure');
}

$outTradeNo = $notifyData['out_trade_no'] ?? '';
$tradeNo = $notifyData['trade_no'] ?? '';
$tradeStatus = $notifyData['trade_status'] ?? '';

$order = findOrderByOutTradeNo($outTradeNo);

if ($order === null) {
    exit('failure');
}

// 还应核对订单金额、app_id、seller_id 等关键字段。
if (in_array($tradeStatus, ['TRADE_SUCCESS', 'TRADE_FINISHED'], true)) {
    markOrderAsPaid($outTradeNo, $tradeNo);
}

exit('success');

注意事项

  • 不要将通知请求的 REMOTE_ADDR 视为付款者 IP。异步通知由支付宝服务器发起,这个地址通常属于支付宝或其网络出口。
  • X-Forwarded-For、X-Real-IP 等请求头可能被伪造。只有请求经过自有或可信代理时,才能使用这些字段。
  • NAT、移动网络、VPN、代理和 IPv6 临时地址都会影响 IP 的准确性,因此不能只凭 IP 判断付款者身份。
  • 必须先验证异步通知签名,再核对 out_trade_no、金额、收款方身份和交易状态。不能因为通知中存在某个字段,就直接把订单标记为已付款。
  • IP 可能涉及个人信息。采集和保存时应明确业务用途,限制保存期限和访问权限,并遵守适用的隐私及数据保护要求。
  • 如果特定支付宝产品的接口文档列出了 client_ip 或类似字段,需要确认它属于请求参数还是通知参数。创建交易时提交的字段不一定会在异步通知中原样返回。

备注:内容仅供参考。