payment processor 基于 IP address 的 Fraud detection 问题
结论
不要为客服付款请求伪造、随机生成或轮换 IP address。客服付款和客户自助付款是两种不同的交易渠道,应该交给 payment processor 按不同的风控配置处理。
建议这样做:
- 客户自助付款继续提交真实的客户 IP address,并保留现有 Fraud detection rules。
- 客服代客付款使用独立的 merchant account、子账户、API credential、payment profile 或 transaction source。
- 客服渠道使用适合人工代客交易的风控规则,例如 MOTO(Mail Order / Telephone Order)、客服辅助交易或 trusted backend flow。
- 如果 payment processor 无法按账户或渠道区分规则,应联系其技术支持调整集成方案,或者为客服渠道更换 processor。
如果 processor 只接受一个 IP 字段,并且无条件对所有交易执行同一套全局 IP 限流规则,应用端就没有真实、可靠的规避方法。
为什么不能简单更换 IP
客服代表所用电脑的 IP address 不是持卡人或付款人的 IP address。它只能表明客服操作来自哪台设备,不能代表付款人的网络位置。
以下做法都不合适:
- 随机生成 IP address;
- 轮换代理服务器或出口 IP;
- 用固定服务器 IP 冒充客户 IP;
- 无法确认来源时,填写客户声称的 IP;
- 随意采用
X-Forwarded-For中未经验证的值。
这些做法会污染风控数据,可能违反 processor 的接口约定,也会增加异常交易的追踪难度。部分 processor 还可能结合账户、设备、银行卡、地址及请求行为,识别这类规避操作。
推荐的渠道拆分方案
两类请求最好有明确且可审计的来源:
Customer browser
-> Customer API
-> Processor profile: ecommerce
-> IP-based fraud rules enabled
Customer service workstation
-> Internal CS API
-> Processor profile: assisted-payment / MOTO
-> Channel-specific fraud rules
这里的 “profile” 是泛称。具体实现取决于 payment processor,可能采用以下名称:
- merchant account;
- sub-merchant;
- payment profile;
- processing account;
- API credential;
- transaction source;
- fraud rule set;
- MOTO / card-not-present channel。
需要查看 processor 的 API 文档或联系其支持团队,确认它提供哪种隔离能力。
请求中应分别记录哪些 IP
客户自助付款时,可以从受信任的反向代理或负载均衡器获取客户 IP:
function getTrustedClientIp(req) {
// 前提:应用只接受受信任代理转发的请求,
// 并且代理会覆盖而不是直接透传客户端提供的该请求头。
return req.headers["x-forwarded-for"]?.split(",")[0].trim()
|| req.socket.remoteAddress;
}
如果公网请求可以直接访问应用服务器,就不能无条件信任 X-Forwarded-For,因为攻击者可以自行构造该请求头。应在负载均衡器、CDN 和应用框架中配置可信代理范围。
客服代客付款时,应记录客服会话信息,但不要将客服工作站 IP 当作持卡人 IP:
const paymentRequest = {
amount: 12500,
currency: "USD",
paymentMethodToken,
channel: "customer_service",
operatorId: authenticatedAgent.id,
sessionId: customerServiceSession.id,
operatorIp: getTrustedClientIp(req)
};
这些字段仅作示意。channel、operatorId 和 operatorIp 能否发送给 processor,以及对应的准确字段名称,都应以其 API 定义为准。应用自己的审计日志仍需保留这些信息。
调用 processor 时,应根据渠道选择不同的配置:
const processorClient =
paymentRequest.channel === "customer_service"
? assistedPaymentClient
: ecommercePaymentClient;
const result = await processorClient.createPayment({
amount: paymentRequest.amount,
currency: paymentRequest.currency,
payment_method: paymentRequest.paymentMethodToken
});
assistedPaymentClient 和 ecommercePaymentClient 应使用不同的 processor credential 或 account profile,不能只在本地更换变量名。
客服渠道仍然需要风控
拆分渠道不代表关闭风控。客服付款通常需要使用另一组信号,包括:
- 客服代表的身份与权限;
- 单个代表的交易频率和金额;
- 客户账户历史;
- payment method fingerprint;
- billing address 或 postal code 校验;
- CVV、AVS 或 3-D Secure 的适用结果;
- 同一卡片跨多个客户账户使用;
- 短时间内连续失败;
- 高金额交易的人工复核;
- 客服账号登录位置或设备异常;
- 客服操作和客户授权记录。
例如,可以在自己的服务中按客服和客户两个维度增加限制:
await riskEngine.assertAllowed({
channel: "customer_service",
agentId: authenticatedAgent.id,
customerId,
paymentMethodFingerprint,
amount,
currency
});
这样既能减少共享 IP 对正常交易的误伤,也能继续检测客服账号滥用、账户接管和异常支付行为。
与 processor 沟通时需要确认的内容
可以向 processor 说明这是 “客服辅助的 card-not-present payment”,并确认以下事项:
- 是否支持 MOTO 或 assisted-payment transaction type;
- 是否能为不同 API credential 配置不同的 Fraud detection rules;
- 是否支持 sub-account 或多个 merchant profile;
- IP 字段表示持卡人 IP、操作员 IP,还是请求服务器 IP;
- 客服交易没有持卡人 IP 时,该字段应该省略、设为
null,还是改用其他字段; - 是否提供 trusted merchant、server-to-server 或 manual review 流程;
- 两个账户的清算、退款、对账和 webhook 能否统一处理。
不要自行猜测 IP 字段是否必填,或可以填写什么值。不同 processor 对字段语义和合规要求可能有不同规定。
如果 processor 不支持渠道隔离
如果 processor 只有一套全局规则,无法区分 credential、merchant account 或 transaction type,可选方案只有:
- 为客服渠道申请另一个 processor account;
- 将客服付款接入支持 MOTO 或渠道化风控的其他 processor;
- 向客户发送安全的付款链接,让客户在自己的设备上完成付款;
- 由客服创建订单,再让客户通过短信或邮件中的一次性链接确认并支付。
安全付款链接通常是最直接的替代方案。processor 可以获取客户真实的网络和设备信号,客服也不必直接处理支付凭据。
无论采用哪种方案,都不应通过伪造或轮换 IP 绕过 Fraud detection rules。问题在于交易渠道的建模方式,应通过账户、凭据或交易类型隔离来解决。
备注:内容仅供参考。
