|
iPhone 上那个六位数的性代验证码,其实只活三分钟。码位苹果在 iOS 系统里把它叫做“一次性代码”(One-Time Code),性代从生成那一刻起就开始倒计时,码位180 秒后自动作废。性代这个设计不是码位随便定的——三分钟够你切换 App、复制粘贴、性代甚至接个电话再回来,码位但又不至于让攻击者有足够时间爆破。性代 我最早注意到这个机制,码位是性代因为一次登录 iCloud 网页版。手机弹窗跳出六位数字,码位我顺手截了个图,性代结果过了五分钟再输入,码位系统直接提示“代码已过期”。性代当时还觉得苹果太抠门,后来查了开发者文档才明白:这六位数背后跑的是 TOTP 算法(基于时间的一次性密码),每 30 秒实际上会刷新一次底层密钥,但苹果为了用户体验,把有效窗口拉长到了 3 分钟。换句话说,你看到的六位数不变,但服务器那边已经换了好几轮“暗号”。 为什么偏偏是六位?四位太短,暴力破解一万次就能撞上;八位又太长,手动输入容易出错。六位数字的组合是 100 万种,配合三分钟限时和尝试次数限制(通常 5 次错误就锁),破解概率低到可以忽略。苹果不是唯一用六位的——Google Authenticator、微软账户、Steam 令牌全是六位。这算是行业默契,不是技术强制。 但 iOS 有个细节做得比别人狠:它会把短信里的验证码自动填充到输入框上方。你收到“【某 App】您的验证码是 483920”,键盘上方直接浮现“483920”的按钮,点一下就行。这个功能叫“自动填充验证码”,从 iOS 12 开始支持。实现原理是系统在后台扫描短信,匹配到“验证码”“code”等关键词且包含六位数字时,才触发填充建议。不是所有短信都配得上这个待遇。 一次性代码的两种来源一种是短信验证码,走运营商通道,苹果只是帮你提取数字。另一种是 iOS 自带的“密码自动填充”里的 TOTP 生成器——你在某个网站开启两步验证时,扫二维码把密钥存进 iCloud 钥匙串,之后打开该网站,键盘上方会直接显示六位动态码,连短信都不用等。后者才是真正的“iOS 一次性代码”,密钥存在本地,离线也能生成。 我试过把同一个 TOTP 密钥同时存进 iPhone 和 1Password,两边生成的六位数完全一致,而且每 30 秒同步跳变。这说明算法是标准 RFC 6238,苹果没魔改。但苹果把刷新周期藏起来了——你看到的六位数在三分钟内不变,其实底层每 30 秒换一次,只是系统帮你“冻结”了显示。这个设计有点鸡贼,但确实减少了用户焦虑。 过期之后发生了什么代码过期不是简单标记一下。服务器端会记录该代码的生成时间戳,收到验证请求时对比当前时间。如果超过 180 秒,直接拒绝,并且不会告诉你“是过期了”还是“输错了”——统一返回“验证码无效”。这是防枚举攻击的常规操作。苹果的服务器还会额外检查该代码是否已被使用过,用过一次立刻作废,哪怕还在三分钟内。 有次我手快,在 iPhone 上生成代码后,又在 iPad 上生成了同一个账户的代码,两个六位数居然不一样。原因是 iCloud 钥匙串同步有延迟,两台设备本地时钟差了 2 秒,TOTP 算法对时间敏感,30 秒窗口错位就导致不同结果。后来我把两台设备都设成自动校时,问题消失。所以如果你遇到“代码明明没错却提示无效”,先检查系统时间是不是手动调过。 六位数字很短,短到可以背下来。但苹果用时间窗口、尝试次数、设备绑定三层锁把它变成了一次性子弹。打完就没了,捡弹壳都没用。 |
