我正在尝试在我的node.js应用程序中正确实现ChaCha20-Poly1305(...加密很困难)。我知道该密码要求每条消息都具有唯一的密钥/密码对,否则安全性就会崩溃。
随机数不必是随机的或不可预测的,因此简单的计数器就足够了。我的问题是我无法弄清楚如何实现一个有效的计数器,该计数器将与在同一台计算机上同时运行的应用程序的多个实例一起工作,并保证不会重复使用现时值。
基本上,我想知道如何避免使用this footgun。
我有一些想法:
- 使用时间戳记。显然not a great idea。
- 使用redis INCR。复杂的开发环境(现在我需要在开发的每台计算机上都安装Redis),但仍然无法保证在意外关机(即使使用Redis AOF)时也不会获得重复的值。
- 每次创建临时数时写入文件或数据库表。这应该可以,但是性能不会很好,而且在意外关闭的情况下,我可能仍然会卡住。
- 使用UUIDv1或v4类型的东西(来自this comment)。最初v1看起来很完美(保证唯一性),但是它与系统MAC地址绑定,因此当我启动该应用程序的多个副本时,我可能会取消任何类型的保证。然后是v4,这应该很好,但是因为随机数只有96位,所以我需要截断ID并增加碰撞概率(实际上v1也是如此)。如果我走这条路线,那是在看nanoid。
- 定期旋转按键。我意识到无论如何都需要这样做,但是我想将它发生的频率降到最低。
- 类似Twitter的Snowflake。 flake-idgen似乎很适合此操作(保证的唯一性,由机器/工人或实例ID进行分区,除了确定实例ID外,不需要协调,就可以生成足够短的ID)。
- 使用XChaCha20-Poly1305。出于这个原因,在libsodium docs中特别推荐(随机数足够大,您可以向其抛出随机值而不必担心)。但是,这还不是一个标准(还?),它将需要使用libsodium进行加密,而不是依靠node的内置OpenSSL包装器。这会使开发复杂化(处理本机绑定)和/或破坏安全性(在JS / WebAssembly中运行加密算法的持续时间问题……超出我的薪资等级)。
我缺少明显的东西吗?人们通常如何解决此类问题?现在,我喜欢flake-idgen,但是似乎没有经过很多审查,因此似乎有些极端情况可能导致重复的id(le秒,leap年,意外服务器时钟)重置,恶意NTP服务器等)。