我发布了一个小型浏览器游戏,包含了全球排行榜。没有什么高科技的东西,仅仅是一个无服务器函数和一个键值存储。几天后,一个可疑的分数出现在排行榜的第一位。然后我注意到版本标签,一个不存在的构建号码。没有人有这个版本号,因为我从来没有制作过它。这就是问题的关键。分数从来没有被玩过,分数是被手动输入的。这是如何工作的,非常简单。函数检查了请求的源头标头,我悄悄地决定这是“安全性”。这不是。源头标头是由发送请求的任何人设置的。CORS只能限制浏览器。它对直接访问端点的脚本无效。所以他跳过了游戏并提交了他想要的任何内容。从我停止被愤怒后,我学到了以下几点: * CORS不是一个认证门户。如果你的板子信任源头标头,它就信任每个人。 * 验证现实,不仅仅是范围。 我检查了字段是否在“范围”内,但我的范围是一个懒惰的大数字,所以一个无意义的版本通过了检查。每个字段都应该限制到实际可能的游戏值。无法实现的值就成了你的欺骗检测器,而不是你的拒绝规则。 * 在提交前放置一个机器人检查。没有令牌的脚本在门口就会死掉。验证令牌在服务器上,不在客户端上。 * 你通常可以找到它们。我的请求日志里包含了源IP地址。匹配伪造的行到精确的写入时间,它是每个伪造行后面的一个地址,没有其他任何地址。打开日志记录在你需要它之前,而不是之后。 * 在实际看到流量的层面上进行封禁。对于无服务器端点,这是函数本身,而不是一些从未看到请求的防火墙规则。天花板,没人会认为这是无懈可击的:一个客户认证的板子是无法被欺骗的。有人使用一个真实的浏览器仍然可以提交一个手选的数字。唯一真正的解决方案是服务器认证,重新运行并确认分数,这是一个更大的工作量。决定一个欺骗是值得什么样的代价在你构建昂贵版本之前。对于一个免费的电子游艺板子,机器人屏障加上诚实的验证是正确的努力。 我将留给你的重新定义。一个活跃的漏洞是免费的渗透测试数据。一个家伙用一行请求就把一个软排行榜变成了一个硬排行榜,并且给我一个可重用的安全设置,每次我下一个游戏时都可以重复利用,并且只花费了一下午。无论你手动编码还是在AI循环中构建,板子都信任客户直到你使其不信任。更好的是从一个随机的欺骗者那里学到的,而不是从发布时。