【发布时间】:2021-07-30 14:27:42
【问题描述】:
我正在生成随机 OTP 样式的字符串,作为短期标识符来链接两个原本不相关的系统(它们在每一端都有身份验证)。这些需要用户读取并重新输入,因此为了降低错误率并减少伪造的机会,我想将其中一个数字作为校验位。目前我的随机字符串符合模式(删除I和O以避免混淆):
^[ABCDEFGHJKLMNPQRSTUVWXYZ][0-9]{4}$
我想为支票附加一位额外的十进制数字。到目前为止,我已经将它实现为一个 BLAKE2 哈希(来自 libsodium),它被转换为十进制并截断为 1 个字符。这仅给出了校验位的 10 种可能性,这并不多。我的主要目标是检测输入中的单个字符错误。
这种方法是可行的,但似乎一个数字不足以检测单个字符错误,并且未检测到的错误很容易找到,例如K37705 和K36705 都被认为是有效的。
我没有在这个 OTP 中加入时间值;相反,它完全是随机的,我依靠记录最近为每个用户生成的 OTP,这些 OTP 会定期删除,并且我正在通过速率和尝试计数限制来减少暴力破解的机会。
我猜BLAKE2在这里不是一个好的选择,但鉴于结果只有10种可能性,我不知道其他人会更好。使用什么算法/方法更好?
【问题讨论】:
-
我认为这不是算法问题。您根本不可能将检测任何这些字符的任意变化所需的信息量编码为单个数字。可能有一些数学可以证明这一点。如果它不是关于任意更改而是关于可能的更改(即 P 与 R、E 与 F 但不是 A 与 Z),它可能会有所不同。
-
与其他校验位相同顺序的校验位可能会更好。一个建议是使用与符号顺序匹配的准群的 Damm 算法。它用于捕获在这种情况下常见的错误,例如两个相邻符号的换位或不正确的符号。
-
虽然与您尝试做的不完全相同,但比特币使用称为 Base58Chcek 的东西来检测比特币地址中的拼写错误并避免出现类似字符。它的工作原理是基本上将有效负载的双 sha256 的最后 4 个字节附加到有效负载,然后对结果进行 base58 编码(以消除看起来相似的字符)。请参阅bitcoin.stackexchange.com/questions/32353/… 了解更多信息。
-
我投票支持迁移到 StackOverflow,因为检测错别字不是安全问题。如果这是一种安全机制,那么您需要以某种方式添加攻击者不知道的密钥;比如校验和需要是(截断的)公钥签名或密钥 MAC。
-
Luhn code 是一种常见但不完善的检查人工转录错误的方法。在信息论意义上,还有其他更优化的方法,并且还有最佳纠错码。加密散列函数在这里不适合。但是,您的用例不会从错误检测中受益。 OTP 代码要么在数据库中,要么不在。您可以选择代码长度、有效期和尝试次数,以保持足够低的猜测概率。
标签: hash one-time-password checksum