卡密安全:防泄露、防超卖、防重复发货
虚拟商品店铺的亏损,很少是被攻击打穿的,多数来自三个低级但高频的漏洞:卡密在后台明文躺着、两个人同时买到最后一张卡、支付回调重试导致同一订单发了两次货。这三件事都能在不动核心系统的情况下修掉。
一、卡密存储:能加密就别明文
卡密是现金。明文存数据库意味着:一次数据库备份泄露、一个被注入的查询、一个离职员工导出的 CSV,都会变成直接损失。
- 入库前用对称加密(AES-256-GCM 或 SM2)存储,密钥放环境变量或独立密钥服务,不进代码仓库;
- 卡密列表页只展示掩码,例如
XXXX-****-****-9F2A,查看明文要二次确认并记账; - 导出功能默认关闭,需要导出时走审批并写审计日志。
二、库存扣减:一条 SQL 解决超卖
“先查库存、再更新库存”是超卖的经典成因。正确做法是让数据库在一句语句里完成判断与扣减:
UPDATE card_pool
SET used = used + 1
WHERE goods_id = ? AND used < total;
影响行数为 1 才算扣减成功,为 0 说明已被抢完,直接返回“库存不足”。任何“查—判—改”的三步写法,在并发下都会多卖。
三、发放幂等:同一订单只发一次
| 环节 | 要求 |
|---|---|
| 回调入口 | 以订单号 + 支付流水号为唯一键,重复回调直接返回成功不再发货 |
| 发放记录 | 发货动作与“已发货”状态在同一事务内提交 |
| 对账任务 | 定时补偿“已支付未发货”的订单,而不是靠人工发现 |
支付平台的异步通知会重试,网络抖动也会让前端重复提交。幂等不是优化,是底线。
四、访问控制:把后台当银行系统
- 后台不与店铺前台同域暴露,或至少加 IP 白名单/二次验证;
- 不同角色分权:客服能查订单但不能看明文卡密;
- 批量操作二次验证,例如一次导出超过 100 条需输入动态码;
- 登录失败次数限制 + 异常登录提醒。
五、日志与告警:出事能查、提前能防
- 记录每一次明文查看、导出、手工改单的操作人、时间、IP;
- 卡密池剩余量低于阈值(如 5%)时推送告警,避免卖出去发不出;
- 同一 IP 短时间大量下单、同一收货账号反复退款,自动进入人工复核;
- 日志保留 90 天以上,覆盖退款争议的处理周期。
六、失效与轮换
发现泄露的第一时间要做的是“作废”,不是“改密码”。因此卡密表需要支持按批次作废:
- 每条卡密带批次号,可按批次一键失效;
- 作废后自动检查是否有未处理订单,必要时人工补发;
- 密钥定期轮换,旧数据用旧密钥解密后再用新密钥加密。
七、交付通道:别把卡密塞进聊天窗口
人工发货时用 IM 发卡密,等于把卡密永久留在第三方服务器上。正确做法是发一条带签名的订单查询链接,让买家自己登录查看,链接带有效期。
八、最小可用检查表
| 项目 | 达标线 |
|---|---|
| 卡密加密存储 | 是 |
| 库存扣减原子化 | 是 |
| 发放幂等 | 是 |
| 明文查看留痕 | 是 |
| 低库存告警 | 是 |
| 批次作废能力 | 是 |
六项里缺两项以上,建议先补技术再放量推广——量越大,漏洞的代价越高。
卡小兔云铺默认提供卡密加密存储、原子扣减、回调幂等与低库存告警,后台明文查看全程留痕,商户不需要自己写这套逻辑。