背景与价值基于一次性密码的二因素需要精确的时间与计数管理。合理的步长、位数与漂移窗口可兼顾安全与体验。统一规范TOTP步长:默认30秒;允许±1窗口漂移。位数:6或8位,推荐6位;统一数字字符集。HOTP重放阻断:计数器单向递增与重放拒绝。核心实现Base32与HOTP生成function base32ToBytes(s: string): Uint8Array { const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; let bits = ''; for (const c of s.replace(/=/g,'').toUpperCase()) { const v = alphabet.indexOf(c); if (v < 0) continue; bits += v.toString(2).padStart(5,'0') } const out: number[] = []; for (let i = 0; i + 8 <= bits.length; i += 8) out.push(parseInt(bits.slice(i, i+8), 2)); return new Uint8Array(out) } async function hmacSha1(key: Uint8Array, msg: Uint8Array): Promise<ArrayBuffer> { const k = await crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']); return crypto.subtle.sign('HMAC', k, msg) } function counterBytes(n: number): Uint8Array { const b = new Uint8Array(8); for (let i = 7; i >= 0; i--) { b[i] = n & 0xff; n >>= 8 } return b } async function hotp(secretBase32: string, counter: number, digits = 6): Promise<string> { const key = base32ToBytes(secretBase32); const mac = await hmacSha1(key, counterBytes(counter)); const u = new Uint8Array(mac); const off = u[u.length-1] & 0xf; const bin = ((u[off] & 0x7f) << 24) | (u[off+1] << 16) | (u[off+2] << 8) | (u[off+3]); const mod = bin % Math.pow(10, digits); return String(mod).padStart(digits, '0') } TOTP验证(时间漂移窗口)function timeStep(stepSec = 30): number { return Math.floor(Date.now() / 1000 / stepSec) } async function totpValid(secretBase32: string, code: string, digits = 6, stepSec = 30, drift = 1): Promise<boolean> { const step = timeStep(stepSec); for (let d = -drift; d <= drift; d++) { const c = await hotp(secretBase32, step + d, digits); if (c === code) return true } return false } HOTP重放阻断(计数器前移)class HotpStore { last = new Map<string, number>(); seen = new Set<string>(); ok(id: string, counter: number): boolean { const l = this.last.get(id) || 0; if (counter <= l) return false; this.last.set(id, counter); return true } } 落地建议TOTP统一步长与位数并提供±1窗口漂移,减少时钟误差造成的失败;敏感操作可提升位数。HOTP计数器单向递增并持久化最近计数,重放拒绝;与设备同步窗口配合使用。验证清单TOTP是否在漂移窗口内通过;HOTP计数器是否前移且重放被拒绝。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部