智能手表如何绑定设备并集成离线支付功能
结论
智能手表绑定手机或其他智能设备时,一般先通过 Bluetooth Low Energy(BLE)发现设备,再用二维码、数字验证码或 NFC 碰一碰确认设备身份,最后由服务端签发设备凭证。
实现离线支付,不能只在手表中增加一个付款页面。开发商还需要具备安全硬件、支付凭证令牌化、交易限额与计数器、密钥管理、挂失和撤销机制,并接入银行、卡组织或持牌支付机构。银行卡 NFC 离线支付通常还要完成 EMVCo、卡组织及相关安全合规认证。开发商不能自行保存银行卡号或复制支付密钥。
开发前,需要先明确“离线支付”指哪种情况:
- 手表离线、收款终端在线:这是最常见、相对容易落地的方式。手表通过 NFC 或动态二维码出示支付凭证,由联网终端完成授权。
- 手表和终端都离线:这是真正的双离线支付。终端需要暂存交易,恢复联网后再清算,因此风险和合规要求更高。
- 封闭场景离线支付:例如园区、校园、交通或门店储值账户,通常比开放式银行卡支付更容易实现。
设备绑定流程
比较稳妥的绑定方式是“BLE 建链 + 用户确认 + 服务端登记”。BLE 配对成功只代表设备之间建立了连接,不能直接视为账号绑定完成。
典型流程如下:
- 手表首次启动时生成设备密钥对,私钥保存在 Secure Element(SE)、eSE、TEE 或其他不可导出的安全存储区。
- 手机应用通过 BLE 扫描手表广播。
- 手机与手表交换临时公钥,并通过 ECDH 协商会话密钥。
- 手表显示一次性验证码,或由手机扫描手表上的二维码。
- 用户确认后,手机将设备标识、公钥、账号令牌和证明材料发送给服务端。
- 服务端验证请求,建立用户、手机和手表之间的绑定关系,并签发短期设备证书或访问令牌。
- 后续通信使用会话密钥加密,并加入随机数、时间戳和递增计数器,防止重放攻击。
二维码或验证码只能用于确认当前绑定的是用户眼前的手表,不能充当长期密钥。
下面是简化后的 Android BLE 发现示例,只展示扫描入口,不包括完整的权限、重连和加密处理:
private val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
if (result.scanRecord?.serviceUuids?.contains(WATCH_SERVICE_UUID) == true) {
bluetoothLeScanner.stopScan(this)
connectAndStartSecureBinding(device)
}
}
override fun onScanFailed(errorCode: Int) {
handleScanError(errorCode)
}
}
fun startWatchScan() {
val filter = ScanFilter.Builder()
.setServiceUuid(WATCH_SERVICE_UUID)
.build()
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build()
bluetoothLeScanner.startScan(
listOf(filter),
settings,
scanCallback
)
}
实际产品还要处理绑定超时、重复绑定、手机更换、恢复出厂设置、设备丢失和远程解绑等情况。
离线支付的实现路线
NFC 银行卡支付
银行卡 NFC 支付一般采用令牌化方案。支付机构不会把真实卡号和发卡行主密钥直接写入手表,而是为具体设备签发受限的支付令牌,再将相关密钥或凭证安全写入 SE。
基本链路如下:
用户绑卡
→ 发卡行或支付机构校验身份
→ Token Service Provider 签发设备支付令牌
→ 凭证安全写入手表
→ 手表通过 NFC 与 POS 交互
→ POS 联机授权或按规则接受离线交易
→ 后续清算
采用这条路线,通常需要与银行、收单机构、卡组织或其认可的服务商合作。手表厂商完成 NFC 通信或 APDU 处理,并不代表已经具备银行卡受理能力。
下面的概念性 APDU 分发代码用于说明手表端支付应用的接口形态。响应值和状态机必须按照实际采用的支付规范确定,不能直接用于生产:
int process_apdu(
const uint8_t *command,
size_t command_len,
uint8_t *response,
size_t *response_len
) {
if (!secure_element_is_ready()) {
return SW_CONDITIONS_NOT_SATISFIED;
}
if (!verify_apdu_sequence(command, command_len)) {
return SW_COMMAND_NOT_ALLOWED;
}
return secure_element_transceive(
command,
command_len,
response,
response_len
);
}
支付密钥应始终在 SE 内使用,不应读取到应用处理器的普通内存。HCE 可以用于部分卡模拟场景,但它能否接入目标支付网络、是否具备所需的离线能力,仍取决于操作系统、安全架构和合作机构的规则,不能默认可行。
动态二维码支付
动态二维码适合手表离线、收款端在线的场景。手表可以预先获取一组受限令牌,付款时根据令牌、计数器和时间窗口生成短时有效的付款码。
概念性载荷可以设计为:
{
"version": 1,
"deviceToken": "opaque-device-token",
"counter": 1842,
"issuedAt": 1789286400,
"nonce": "random-value",
"signature": "base64url-signature"
}
签名示意:
signature = Sign(
devicePrivateKey,
SHA-256(version || deviceToken || counter || issuedAt || nonce)
)
收款端或支付后台必须检查签名、令牌状态、计数器和使用次数。付款码不能长期保持不变,否则被截图复制后可能遭到重复使用。
如果手表需要长时间离线,可以预置数量有限的一次性支付令牌。每个令牌只能使用一次,同时要设置有效期、单笔限额和累计限额。令牌耗尽后,手表必须联网补充。
封闭账户或储值支付
园区、交通、校园等封闭场景可以使用自有账户和清算系统。进行双离线交易时,手表和终端可以共同维护计数器,终端恢复联网后再上传交易。
服务端可以按照类似逻辑检查交易:
public PaymentResult verifyOfflinePayment(OfflinePayment payment) {
Device device = deviceRepository.findActive(payment.deviceId());
if (device == null) {
return PaymentResult.reject("DEVICE_NOT_ACTIVE");
}
if (!signatureService.verify(
device.publicKey(),
payment.signedPayload(),
payment.signature())) {
return PaymentResult.reject("INVALID_SIGNATURE");
}
if (payment.counter() <= device.lastAcceptedCounter()) {
return PaymentResult.reject("REPLAY_DETECTED");
}
if (payment.amount().compareTo(device.remainingOfflineLimit()) > 0) {
return PaymentResult.reject("OFFLINE_LIMIT_EXCEEDED");
}
return PaymentResult.acceptPendingSettlement();
}
生产系统还必须处理并发终端、计数器跳号、重复清算、退款、冲正和终端时钟不可信等问题,不能只依靠上述检查。
开发商的落地步骤
第一步是确定支付边界,包括使用 NFC 还是二维码、面向银行卡还是封闭账户,以及只允许手表离线,还是要求手表与终端双离线。不同选择对应的资质要求、技术方案和风险成本差别很大。
接下来要确认硬件是否具备 NFC 控制器、SE/eSE、设备唯一密钥、安全启动、固件签名、调试口关闭和防回滚机制。如果设备没有可信的密钥存储,就不适合承载可直接付款的长期凭证。
服务端至少需要具备以下能力:
- 设备注册、绑定、解绑和状态查询。
- 支付令牌申请、写入、续期和撤销。
- 风险限额、离线次数和累计金额控制。
- 设备丢失挂失、黑名单和远程停用。
- 交易上传、去重、冲正、退款和清算。
- 密钥轮换、审计日志和异常告警。
基础系统完成后,还要与银行、支付机构或卡组织联调并接受认证。具体认证项目取决于支付网络、销售地区、硬件方案和业务角色,正式清单应由合作机构提供。
安全与合规注意事项
不要在手表、手机应用、日志或普通数据库中保存 CVV、支付主密钥,或其他可被直接滥用的完整银行卡数据。需要保存卡号相关信息时,应尽量使用支付令牌,并确认系统是否进入 PCI DSS 等合规范围。
离线交易无法实时查询余额、挂失状态和风险名单,因此必须设置:
- 单笔金额上限。
- 离线累计金额上限。
- 连续离线交易次数上限。
- 凭证有效期和强制定期联网要求。
- 设备解锁、PIN 或生物识别条件。
- 重放检测和终端交易去重机制。
系统也不能完全依赖手表时间,因为本地时钟可能被修改。更稳妥的方式是结合签名计数器、最近一次可信的服务端时间、令牌批次和有效窗口进行判断。
设备恢复出厂设置时,应删除本地支付凭证,并使旧令牌失效。如果只清除界面数据,却没有撤销服务端令牌,实际支付风险仍然存在。
推荐方案
首次开发时,可以先采用“BLE 安全绑定 + 动态二维码 + 收款端联机验证”,也可以先在园区等封闭场景中试点,用来验证设备绑定、令牌生命周期和风控系统。
如果目标是银行卡 NFC 支付,应尽早确定支付合作机构和通过认证的 SE 方案,再根据合作方提供的令牌化、个人化及认证规范进行开发。不要等到硬件定型后才开始接洽,因为 SE、NFC 路由和设备安全架构都可能影响最终的认证结果。
备注:内容仅供参考。