如何正确实现Unicode密码?

8

为开发人员增加对Unicode密码的支持是一个重要的功能,不应忽视。

但是,在密码中添加对Unicode的支持是一项棘手的工作,因为相同的文本在Unicode中可以以不同的方式编码,您不希望因此阻止人们登录。

假设您将密码存储为UTF-8格式,请注意,此问题与Unicode编码无关,而与Unicode规范化有关。

现在的问题是:您应该如何 规范化 Unicode数据?

您必须确保您能够进行比较。您需要确保当下一个Unicode标准发布时,它不会使您的密码验证失效。

注意:仍有一些地方可能永远不会使用Unicode密码,但这个问题不是为什么或何时使用Unicode密码,而是如何以正确的方式实现它们。

第一个更新

是否可以使用操作系统进行规范化,而不是使用ICU实现这个?


1
另一个Unicode标准发布会有什么不同?您已经决定将密码存储为UTF-8-因此请将密码存储为UTF-8。委员会可以发布新的标准,而无需强制您更改存储数据的方式。 - Dominic Rodger
Unicode并不规定编码方式。它只是一个包含每个字符及其对应编号的列表(基本上是这样)。如果您选择UTF-8,我不知道这种编码方式将来会以何种方式发生变化,从而破坏兼容性。 - Assaf Lavie
有多种方式可以编码相同的视觉字符,我假设这就是他想知道如何处理的问题。 - Lasse V. Karlsen
2
也许我表达不够清楚,这不是关于Unicode编码的问题,而是关于Unicode文本规范化的问题,这个过程是为了能够进行字符串比较而必需的。我修改了问题以澄清这一点。 - sorin
一个非常相似的问题(“在哈希密码时,什么Unicode规范化(和其他处理)是适当的?”)有一个深入的答案(https://dev59.com/wGQo5IYBdhLWcg3wSNtw#74497817),截至2022年11月,引用了现在控制RFC 8264和8265的PRECIS框架,该框架取代了StringPrep。 - Jim Ratliff
2个回答

6
一个好的开始是阅读Unicode TR 15: Unicode Normalization Forms。然后你会意识到这需要很多工作,而且容易出现奇怪的错误 - 你可能已经知道了这一点,因为你在这里提问。最后,你可以下载像ICU这样的东西,让它为你完成这些工作。
我IRC,这是一个多步骤的过程。首先,你要将序列分解到不能再分解为止 - 例如,é将变成e + ´。然后你将序列重新排序成一个定义良好的顺序。最后,你可以使用UTF-8或类似的编码将结果字节流进行编码。UTF-8字节流可以输入到你选择的加密哈希算法中并存储在持久存储器中。当你想检查一个密码是否匹配时,执行相同的过程并将哈希算法的输出与数据库中存储的内容进行比较。

0
一个问题回到你那里- 你能解释一下为什么要添加“不使用ICU”吗?我看到很多问题要求ICU做的事情(我们认为)非常好,但是“不使用ICU”。只是好奇。
其次,您可能会对StringPrep / NamePrep感兴趣,而不仅仅是规范化:StringPrep-将字符串映射为比较。
第三,您可能会对UTR#36UTR#39中的其他Unicode安全性问题感兴趣。
*(披露:ICU开发人员 :))

我并不反对ICU,但在某些情况下,它的大小可能是一个真正的问题。因此,您可能希望使用特定于操作系统的API。 - sorin
如果你只是使用规范化,你可以很容易地缩小代码和数据的大小。此外,ICU通常作为一个模块安装。谢谢您的回复。 - Steven R. Loomis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接