← LinkPay 接口文档

域名白名单与 H5 防转发

用于降低商户生成的 LinkPay H5 链接被复制到其他网站、浏览器或设备使用的风险。签名、订单号、金额、回调和退款继续使用现有 V1 / V2 协议。

商户默认处于观察模式。开启严格模式前,必须完成域名审核与下面的浏览器入口接入。只配置白名单、只检查 Referer 或加前端脚本,都不能单独防止链接转发。

1. 申请和审核域名

  1. 在独立商户后台 → 域名白名单,提交站点名称、完整来源地址和固定接续页。
  2. 来源地址按完整 origin 匹配,例如 https://shop.example.com;不同子域名需分别申请。不支持泛域名、用户名密码、IP、尾点和非 443 生产端口。
  3. 按页面显示添加 DNS TXT 记录 _linkpay-verify.shop.example.com,或在 /.well-known/linkpay-verification.txt 放置指定文本。验证值有效 24 小时,必须与当前申请完全一致。HTTPS 文件读取验证公网地址、TLS、重定向站点及体积。
  4. 点击“验证归属”。校验通过后,总后台 → H5 安保 → 域名白名单进行审核。证明超过 30 天不能直接批准,需要重新验证。
  5. 先在观察模式完成下面的接入,再由总后台设置严格模式。重新申请验证会撤销原站点版本,旧付款会话随即失效。

2. 浏览器先建立入口授权

在已批准商户页面,由用户当前浏览器以顶层表单 POST 跳转到平台。后端生成至少 24 位随机 state,并将它与当前已登录用户、待支付业务订单及短时有效期绑定在服务端会话中。不要把商户密钥放到浏览器。

<!-- action 改为你的 LinkPay HTTPS 域名;两个值由商户后端生成 -->
<form method="post" action="https://pay.linkapay.xyz/cashier/security/bootstrap">
  <input type="hidden" name="site_id" value="审核通过的站点ID">
  <input type="hidden" name="state" value="商户生成并保存的随机state">
  <button type="submit">前往付款</button>
</form>

平台验证 Origin / Referer 是否属于这个站点,建立 HttpOnly、Secure、SameSite=Lax 的第一方浏览器会话,然后跳回申请时填写的固定接续页。不要嵌在 iframe,也不要在服务器上代替用户完成入口请求。入口页需允许发送来源信息;若 no-referrer 等隐私设置令浏览器只发送 Origin: null,平台会拒绝该入口,请对付款入口页使用 strict-origin-when-cross-origin 等保留来源域名的策略。

https://shop.example.com/pay/continue?h5_entry=64位授权码&state=原state

商户接续页必须验证登录会话、state、业务订单归属与有效期,并消费 state 防止跨订单复用;然后由商户后端执行签名下单。建议短时在服务端保存这一订单的授权码用于相同订单重试。接续页应返回 Cache-Control: no-store、Referrer-Policy: no-referrer,处理后立即跳到不含授权码的地址,避免第三方资源、分析脚本和含查询串的访问日志记录它。

3. V1 / V2 下单增加 h5_entry

字段规则
h5_entry64 位小写十六进制字符串。严格模式必须填写,并参加原有 MD5 / RSA 签名。
入口授权创建后 120 秒内完成第一次绑定,只能绑定一个商户的一笔订单。
重复请求同一笔订单必须使用原授权码,金额、标题及回调地址必须一致。重新提交授权码不表示重新扣款。
付款会话上限 24 小时,实际发起支付仍受订单自身有效期约束;Cookie、站点版本或会话撤销会导致读取被拒绝。
// 伪代码:继续使用现有 LinkPay SDK 的签名算法与字段编码
params = 原来的下单字段;
params.h5_entry = 接续页验证成功后取得的授权码;
params.sign = 按原 V1 MD5 或 V2 RSA 规则对全部签名字段重新签名;
POST /mapi.php        // V1
POST /api/pay/create  // V2
// 页面跳转接口同样接受 h5_entry,请优先使用 POST。

严格模式下,V1 返回平台 payurl,V2 返回 pay_type=jump 和平台 pay_info。商户须将原浏览器跳转到平台地址,不再从 API 取得上游二维码、表单或 JSAPI 参数。严格模式适用于受控 H5 路径,原生 APP / 小程序 / 直接 JSAPI 等模式需要独立适配,不能在未联调时直接开启。

入口授权必须在付款链接生成之前完成。收银台、状态查询、身份授权接续、再次选路及商户订单详情都会应用相应校验或脱敏。绑定浏览器正常刷新和更换网络不会仅因 IP / UA 改变而被拒绝;缺少或失效 Cookie 时需返回商户处理。

4. 跨设备付款

原设备在收银台点击“换设备付款”,目标设备扫码或打开接续链接,点击“获取确认码”。原设备输入目标设备展示的六位码并确认,授权才会转移。接续链接有效两分钟,同一申请最多五次确认尝试。确认后原设备无法继续读取付款数据;再次发起会取消前一条待确认申请。单纯转发订单地址不会自动绑定接收人的浏览器。

5. 后台策略、监控和操作记录

模式 / 操作行为
观察记录未接入订单和访问情况,保持现有调用可用。
严格防转发新下单要求授权码;付款数据要求匹配浏览器和有效站点版本。切换时,尚未绑定的历史链接也会被拒绝,应先排空在途订单。
限时豁免仅放行新订单的入口要求,必须填写原因和不超过 90 天的期限;到期自动按严格模式处理。已绑定严格模式的订单持续受保护。
暂停新支付禁止创建新的付款尝试。要阻止已有付款信息读取,应同时暂停域名或撤销指定会话。
域名暂停 / 撤销旧站点版本的付款会话失效。恢复域名需要重新建立付款会话,不能自动复活旧链接。

总后台可查看 IP、IP 来源、站点、订单、校验结果与浏览器标签;商户只能查看自身的脱敏记录;代理仅能只读授权范围内的站点状态及事件,不展示原始 IP、会话令牌和订单标识。管理员审核、策略调整、会话撤销继续写入管理员操作日志和业务审计。

重复的相同服务端事件在 60 秒内合并,计数并非浏览器访问总次数。异常记录不自动封禁商户。事件保留 90 天,由后台任务分批清理;数据库写入失败时,最多暂存 200 条事件到私有 runtime/h5-risk-pending,后台任务自动重放。持续异常应检查磁盘、数据库和任务运行情况。严格订单绑定记录持续保留,避免清理后降级放行。

6. 上线与验证

  1. 备份数据库和代码,部署新增迁移 202610060002_linkpay_h5_security,使用具有 DDL 权限的迁移账号执行原有升级命令。运行账号仍使用原有 DML 权限。
  2. 发布对应的 frontend 构建资源,重启 HTTP 及后台任务。生产必须使用正确 HTTPS 站点地址;仅“demo 开启 + _dev/_test 数据库 + 回环站点”的本地组合允许 HTTP。
  3. 让一个测试商户完成域名验证、原浏览器下单、复制链接到无痕窗口被拒绝、原设备确认跨设备成功四步,再开启其他商户。开启严格模式前处理完旧在途订单。
  4. 确认真实上游支付回调、通知和结算正常。H5 风控不会更改真实支付结果,不会因链接被拦截而跳过已到账资金的处理。

能力边界

这套机制防护的是 LinkPay 控制范围内的 H5 入口和付款数据读取。商户主动用白名单站点做代理、泄露完整浏览器 Cookie、截图已展示的二维码,或转发用户已经取得的第三方支付地址,仍可能绕过这一层控制。需要更强约束时,应结合上游“绑定付款人 / 限时令牌”等能力逐通道接入,不能承诺只凭域名白名单彻底杜绝外放。