-- 商户端手输 6 位数字核销码的失败计数与锁定。
|
--
|
-- 核销码本来就下发一个 6 位数字码给顾客(order_dynamic_verification_code.display_code),但系统里
|
-- 没有任何地方能输入它:相机不好用或屏幕反光时,商户只能让顾客反复刷新二维码。补上手输入口的同时
|
-- 必须限次——数字码只有 100 万空间,不限次就是一个可以暴力枚举的核销入口。
|
--
|
-- 计数按「谁在输」记(商户 + 门店 + 操作员):连续输错到上限就锁定一段时间,锁定期间连校验都不做,
|
-- 否则攻击者仍然可以用「这次报错是无效码还是已锁定」把枚举继续下去。
|
--
|
-- 幂等:`create table if not exists` 在 MySQL 5.7 与 8.0 上都能直接重复执行,所以这份迁移也可以
|
-- 用 scripts/apply-sql-file.ps1 直接落到开发库(开发库 Flyway 关闭、结构不由迁移维护)。
|
create table if not exists merchant_numeric_code_attempt (
|
id bigint not null auto_increment,
|
merchant_id bigint not null,
|
store_id bigint not null,
|
operator_id bigint not null,
|
consecutive_failures int not null default 0 comment '连续输错次数,成功或锁定时归零',
|
locked_until datetime default null comment '锁定到期时间,未锁定为 NULL',
|
last_attempt_at datetime not null default current_timestamp,
|
primary key (id),
|
unique key uk_merchant_numeric_code_attempt (merchant_id, store_id, operator_id)
|
) engine=InnoDB default charset=utf8mb4 comment='商户端手输数字核销码的失败计数与锁定';
|