Alice在OopsSec Store买了张500美元礼品卡,填写收件人邮箱后,她收到了格式为XXXX-XXXX-XXXX的代码。出于好奇,她点击了“重发邮件”,界面却永远只显示“邮件服务暂不可用”。而此时此刻,另一个账号Bob仅仅靠卡片创建时间精确到毫秒的那串数字,就已经把她的余额全部转走了。
漏洞的根源埋在lib/gift-card.ts文件里一段十行的线性同余生成器(LCG)。代码用硬编码的乘数1103515245和增量12345,从32位的状态值一步步迭代,截取高16位模除字母表长度,依次取出12个字符拼成礼品卡代码。种子呢?正是礼品卡的createdAt毫秒时间戳。
打开网易新闻 查看精彩图片
更危险的是,这个毫秒级的时间戳毫不遮掩地同时暴露在/profile/gift-cards页面和GET /api/gift-cards接口的响应中。在Alice的卡详情里,字段createdAt显示为“2025-01-15T10:42:33.456Z”,其中“.456”不是格式美化,它就是种子本身。API虽然刻意隐藏了code字段,却大剌剌把种子交给了所有人。
还原过程出奇简单。攻击者Bob登录自己的账号后,拿到API返回的createdAt,提取出毫秒值作为种子,调用同样的nextState函数循环12轮,每轮取出对应字母,就得到了和Alice邮箱里一模一样的礼品卡代码。没有解密、没有爆破,只是把开源仓库里的生成逻辑原样跑了一遍。
这一漏洞展示了即使被设计为“只返回元数据”的接口,也可能因为暴露生成参数而完全瓦解安全假设。对于任何将时间戳、序列号当作随机源的应用,本文案例都是一个醒目的提醒:不要让种子与数据同包发送,不要以为隐藏原始值就能切断重现路径,硬编码的LCG在任何可预测输入面前都只是一层薄纸。
热门跟贴