PAYATHON 2026

如何防范假冒闲鱼页面利用平台充值实施支付诈骗?

支付小周

结论

单纯增加订单参数或提高接口的“构建难度”,解决不了这类诈骗。真正有效的做法,是把充值、订单和支付对象绑定在一起,并确保只有真实登录用户才能在可信的业务流程中创建、确认订单。

建议同步落实以下措施:

  1. 将充值资金与用户、订单及用途绑定,禁止使用他人充值为任意订单付款。
  2. 由服务端生成一次性支付凭证,金额、收款对象等关键参数不能由前端自行提交。
  3. 支付前清楚展示真实商户、商品和资金用途,并要求用户再次确认。
  4. 建立订单状态机、风控规则和异常拦截机制。
  5. 严格验证支付回调,不能把“到账”直接视为业务成功。
  6. 对疑似诈骗充值延迟开放使用,并配合人工审核和应急冻结。
  7. 保存相关证据,及时向闲鱼、支付机构和公安机关举报。

目标不是让攻击者“更难拼出一个订单”,而是让脱离真实业务场景的订单即使被拼出来,也无法完成支付,更不能产生可消费、转移或提现的资金价值。

为什么会出现这种诈骗

这类骗局通常不只是接口被破解,而是社会工程与业务流程漏洞共同造成的。

诈骗者会制作假的闲鱼商品页、客服页或支付页,让受害者误以为自己正在闲鱼购买商品。随后,他们引导受害者进入真实平台充值,或者向受害者提供预先构造的订单信息。

平台存在以下设计时,风险会明显增加:

  • 任何人都可以直接创建指定金额的充值订单。
  • 充值到账后变成通用余额,可立即购买、转账或提现。
  • 订单金额、商品名称和收款账户由前端提交。
  • 系统不校验订单创建者、登录用户与付款用户是否一致。
  • 支付链接长期有效,或者可被多人重复打开。
  • 支付页面没有醒目展示真实平台名称和资金用途。
  • 系统只根据前端跳转结果判断支付成功。
  • 新用户大额充值后可以立即消费或转移资金。

治理时应重点绑定身份、资金用途和业务上下文,而不是只增加几个隐藏参数。

将充值与具体订单强绑定

业务允许的情况下,应优先取消“先充值通用余额,再任意消费”的模式,让用户直接为具体商品付款。

如果业务确实需要充值,至少要记录以下信息:

  • user_id:充值所属用户。
  • business_order_id:对应的业务订单。
  • purpose:资金用途。
  • amount:服务端计算的金额。
  • merchant_id:实际收款或服务提供方。
  • expires_at:支付凭证过期时间。
  • nonce:一次性随机值。
  • risk_status:风控状态。

充值到账后,资金只能用于已经绑定的业务订单,不能直接进入可自由消费、转赠或提现的余额。

例如:

充值单 R1001
├── 用户:U2001
├── 业务订单:O3001
├── 用途:PURCHASE_GOODS
├── 金额:299.00
├── 可支付对象:M4001
└── 失效时间:2026-09-13 15:30:00

用户取消订单后,可以按原支付渠道退款,但不能简单地把资金转成可供其他账户或其他订单使用的通用余额。

关键订单数据必须由服务端生成

前端只应提交商品、规格、数量等业务选择。最终金额、商户、优惠、手续费和收款对象,都必须由服务端根据数据库中的有效数据计算。

错误做法:

POST /api/payment/create

{
  "amount": 9999,
  "merchantId": "attacker-controlled-id",
  "subject": "闲鱼商品"
}

这种接口实际上允许调用方自行决定“付多少钱、付给谁、买什么”。

更合理的接口只接收必要的业务标识:

POST /api/orders/O3001/payment-intents

{
  "paymentMethod": "ALIPAY"
}

服务端应完成以下校验:

async function createPaymentIntent(
  userId: string,
  orderId: string,
  paymentMethod: string
) {
  const order = await orderRepository.findById(orderId);

  if (!order) {
    throw new Error("ORDER_NOT_FOUND");
  }

  if (order.userId !== userId) {
    throw new Error("ORDER_OWNER_MISMATCH");
  }

  if (order.status !== "PENDING_PAYMENT") {
    throw new Error("INVALID_ORDER_STATUS");
  }

  if (order.expiresAt.getTime() <= Date.now()) {
    throw new Error("ORDER_EXPIRED");
  }

  const amount = calculateAmountOnServer(order);
  const nonce = crypto.randomUUID();

  return paymentIntentRepository.create({
    orderId: order.id,
    userId,
    merchantId: order.merchantId,
    amount,
    currency: "CNY",
    purpose: "PURCHASE_GOODS",
    paymentMethod,
    nonce,
    status: "CREATED",
    expiresAt: new Date(Date.now() + 10 * 60 * 1000)
  });
}

除了订单归属、状态和有效期,服务端还要确认商品仍然有效、价格没有变化、库存可用,并验证当前用户是否有权购买该商品。

使用短时、一次性的支付凭证

支付链接中不应直接包含可随意修改的业务参数。服务端可以签发短时有效的 payment_token,其中包含支付意图编号、用户、用途、随机数和过期时间。

下面是一个简化的 HMAC 签名示例:

import crypto from "node:crypto";

function signPaymentIntent(
  intentId: string,
  userId: string,
  expiresAt: number,
  nonce: string,
  secret: string
): string {
  const payload = `${intentId}.${userId}.${expiresAt}.${nonce}`;

  return crypto
    .createHmac("sha256", secret)
    .update(payload, "utf8")
    .digest("base64url");
}

function verifyPaymentIntent(
  intentId: string,
  userId: string,
  expiresAt: number,
  nonce: string,
  signature: string,
  secret: string
): boolean {
  if (Date.now() > expiresAt) {
    return false;
  }

  const expected = signPaymentIntent(
    intentId,
    userId,
    expiresAt,
    nonce,
    secret
  );

  const actualBuffer = Buffer.from(signature);
  const expectedBuffer = Buffer.from(expected);

  return (
    actualBuffer.length === expectedBuffer.length &&
    crypto.timingSafeEqual(actualBuffer, expectedBuffer)
  );
}

签名校验只能证明参数没有被篡改,不能替代用户身份、订单归属和订单状态校验。数据库还要记录 nonce 是否已经使用。支付凭证一旦使用或过期,应立即失效。

密钥不能放在前端代码、移动端安装包或支付链接中。它应保存在服务端密钥管理系统中,并定期轮换。

绑定创建者、登录者和付款上下文

用户不能仅凭一个链接直接进入付款环节。打开支付页面时,系统应重新确认登录状态,并完成以下校验:

当前登录用户 == 订单所有者
当前订单 == 支付凭证绑定订单
当前金额 == 服务端计算金额
当前商户 == 订单绑定商户
当前用途 == 支付凭证绑定用途
当前状态 == PENDING_PAYMENT

如果业务支持代付,应设计独立的代付流程,清楚展示“你正在为谁的哪一笔订单付款”,并限制代付资金的使用范围。不能通过放宽普通充值接口来支持代付。

系统还要防止攻击者把自己的订单链接直接发给受害者。可以采取以下措施:

  • 支付前再次验证登录密码、短信验证码或设备确认。
  • 对新设备、高风险 IP 和异常地区触发强化验证。
  • 将支付凭证与当前会话或设备进行风险绑定。
  • 拦截同一订单频繁更换设备访问的行为。
  • 禁止未登录用户直接拉起支付渠道。

用户可能正常更换设备或浏览器,因此设备绑定不能作为唯一依据,更适合作为一个风险信号。

在支付页明确揭示真实交易对象

假页面诈骗利用的是用户对交易对象的误判。支付确认页应醒目展示以下内容:

  • 当前平台的正式名称和备案域名。
  • 实际购买的商品或服务。
  • 实际收款主体。
  • 支付金额和资金用途。
  • 订单创建时间及失效时间。
  • 明确提示“本平台充值不等同于闲鱼付款”。

例如:

你正在向“某某平台”充值 2,000 元。该操作不是闲鱼订单付款,闲鱼卖家无权要求你通过本页面充值。若有人通过聊天、二维码或远程指导要求你操作,请立即停止。

这类提示不能只放在用户协议或页面底部。遇到大额充值、新用户首次充值、从外部链接访问等高风险场景,应通过弹窗、勾选确认或输入交易对象名称等方式,要求用户主动确认。

建立严格的订单状态机

客户端不能任意指定订单状态,用户访问支付成功页也不代表订单已经付款。

可以采用类似的状态:

CREATED
  ↓
PENDING_PAYMENT
  ↓
PAYMENT_PROCESSING
  ↓
PAID
  ↓
FULFILLED

异常分支包括:

CANCELLED
EXPIRED
PAYMENT_FAILED
RISK_REVIEW
REFUNDING
REFUNDED

每次状态变化都要检查事件来源和前置状态。例如,只有收到支付机构的服务端回调并完成验签后,订单才能从 PAYMENT_PROCESSING 进入 PAID。

更新状态时,可以通过条件更新避免并发重复处理:

UPDATE payment_intent
SET status = 'PAID',
    paid_at = CURRENT_TIMESTAMP
WHERE id = :intent_id
  AND status = 'PAYMENT_PROCESSING'
  AND amount = :callback_amount;

如果受影响的行数不是 1,系统应停止发货或余额入账,转入幂等检查或人工审核。

严格校验支付机构回调

支付结果应以支付机构的服务端异步通知和主动查询结果为准。不同支付机构使用的字段和签名算法不同,具体实现应参照其当前官方文档。

通常至少要校验:

  • 回调签名是否有效。
  • 商户号和应用编号是否属于本平台。
  • 支付机构交易号是否唯一。
  • 商户订单号是否存在。
  • 回调金额和币种是否完全一致。
  • 订单当前状态是否允许入账。
  • 收款账户是否为预期账户。
  • 回调是否发生在合理时间范围内。
  • 重复回调是否经过幂等处理。

不能相信客户端提交的以下信息:

{
  "paid": true,
  "amount": "299.00",
  "transactionId": "xxx"
}

前端跳转页只能显示“正在确认支付结果”,不能据此发货、增加余额或修改订单状态。

对异常充值设置资金冷静期

如果平台余额可以购买高流动性商品、兑换卡券、转账或提现,平台就可能被用作诈骗资金的中转渠道。

可以根据风险等级采取不同限制:

  • 暂缓新注册账户首次大额充值的资金使用。
  • 充值后立即购买卡券、虚拟商品或高流动性资产时触发审核。
  • 充值账户与消费账户不一致时直接拦截。
  • 短时间内多名用户为同一对象付款时告警。
  • 同一设备、IP、银行卡或收款对象关联大量账户时告警。
  • 充值金额与正常客单价明显不符时要求二次验证。
  • 高风险资金只能原路退款,不得转到其他账户。
  • 将疑似诈骗订单转入 RISK_REVIEW,暂停发货、提现和资金转移。

风控阈值应根据平台的真实交易数据制定。只设置固定金额阈值,很容易被拆单绕过。系统还要统计一定时间窗口内的累计金额、订单数量、关联账户和行为序列。

增加接口滥用防护

订单和支付接口还应具备常规的安全控制:

  • 登录认证与权限校验。
  • CSRF 防护。
  • Origin、Referer 辅助校验。
  • 接口限流和频率控制。
  • 图形验证码或行为验证。
  • 幂等键。
  • 防重放随机数。
  • 短时有效期。
  • WAF 和机器人识别。
  • 完整的审计日志。

幂等键示例:

POST /api/orders/O3001/payment-intents
Authorization: Bearer <access_token>
Idempotency-Key: 3a27d071-5cca-4eb9-8670-9ac145046895
Content-Type: application/json

服务端应确保相同用户、相同订单和相同 Idempotency-Key 不会生成多笔可支付订单。

Referer 校验和前端页面来源限制只能作为辅助措施。攻击者既可以通过自己的服务器直接调用接口,也可能诱导受害者打开真实页面。来源校验无法解决身份和资金归属问题。

监测假冒页面和异常订单

平台可以从外部假冒页面和内部异常订单两个方向开展监测。

外部假冒页面监测包括:

  • 搜索品牌名、域名和常见拼写变体。
  • 监测新注册的相似域名。
  • 收集仿冒页面截图、URL、二维码和聊天记录。
  • 检查搜索广告、短链接和社交平台传播内容。
  • 为官方域名部署 HTTPS,并配置安全响应头。
  • 在官网公布唯一域名、官方客服和核验入口。

内部订单监测包括:

  • 某个商品或金额突然被大量创建。
  • 大量充值来自新用户。
  • 同一支付链接被不同账户或设备访问。
  • 多笔充值最终流向同一商品、商户或提现账户。
  • 下单、充值、消费和提现在极短时间内连续完成。
  • 用户从外部聊天工具或短链接进入支付页。

风险日志应记录订单号、用户、设备、IP、请求时间、支付渠道交易号和状态变化,但不能记录完整银行卡号、支付密码等敏感信息。

事件发生后的处理流程

发现诈骗正在发生时,应先控制资金并保全证据:

  1. 暂停相关订单的发货、提现、转账和余额消费。
  2. 标记并隔离涉诈账户、设备、IP、商户和关联订单。
  3. 保存访问日志、订单日志、支付回调、账户关系和操作记录。
  4. 联系支付机构申请风险处置,确认能否止付或原路退款。
  5. 向闲鱼投诉假冒页面、账号、商品和聊天内容。
  6. 向域名注册商、托管商和安全平台投诉仿冒域名。
  7. 引导受害者保存付款记录、聊天记录、链接和截图,并及时报警。
  8. 根据司法机关或支付机构的正式要求提供证据。

冻结资金和账户时,应遵守平台协议、适用法律及内部授权流程。如果暂时无法确认责任归属,不要把款项退到聊天中临时提供的新账户,原则上应优先通过原支付渠道退款。

不建议采用的方案

以下措施可以略微增加攻击成本,但不能作为主要防线:

  • 仅增加隐藏字段。
  • 对订单参数做 Base64 编码。
  • 混淆前端 JavaScript。
  • 隐藏 API 地址。
  • 频繁修改 URL 路径。
  • 只校验 Referer。
  • 只在页面底部增加免责声明。
  • 只限制单笔充值金额。
  • 依赖复杂订单号防止猜测。

这些做法既无法阻止攻击者通过正常页面创建真实订单,也无法阻止其诱导受害者主动操作。

推荐的实施优先级

建议按以下顺序改造:

  1. 立即切断“任意充值、任意消费、快速提现”的资金链路。
  2. 强制绑定用户、业务订单、金额、商户和资金用途。
  3. 改由服务端计算所有关键数据。
  4. 使用短时、一次性支付凭证。
  5. 在支付页面醒目展示交易对象,并增加反诈骗确认。
  6. 严格验证支付回调,完善订单状态机。
  7. 为高风险充值设置冷静期和人工审核。
  8. 建立账户、设备、资金和订单之间的关联风控。
  9. 完善投诉、冻结、退款、取证和报警流程。

落实这些措施后,即使诈骗者复制页面、获取订单链接,或者诱导用户进入真实充值页,也很难再把受害者的资金变成自己能够消费、转移或提现的资产。

备注:内容仅供参考。