如何防范 Unicode 安全漏洞
How to Protect Against Unicode Security Vulnerabilities
"Five things everyone should know about Unicode" 是一篇博客 post,展示了如何将 Unicode 字符用作网站的攻击媒介。
此类真实世界攻击的主要示例是提交到 Google Play 商店的虚假 WhatsApp 应用程序,在开发者名称中使用了不可打印的 unicode space,这使得名称独一无二并允许它通过 Google 的过滤器。蒙古元音分隔符 (U+180E) 就是这样一种不可打印的 space 字符。
另一个漏洞是使用看起来相似的替代 Unicode 字符。 Mimic 工具展示了它的工作原理。
我能想到的一个例子是在注册新用户时保护用户名。您不希望两个用户名相同或看起来相同。
你如何防止这种情况发生?那里有这些角色的列表吗?从所有表单输入中删除所有这些类型的字符是否应该成为一种常见的做法?
当您拥有已知安全值的白名单并排除所有其他值时,所有清理工作效果最佳。
ASCII 就是这样的一组字符。
这可以通过多种方式来解决,但是每一种方式都可能会增加误报的数量,从而引起合法用户的烦恼。此外,其中 none 将适用于 100% 的情况(即使合并)。他们只会添加一个额外的层。
一种方法是创建具有相似字符的表,并检查是否存在重复名称。 'look similar' 的含义在很多情况下是主观的,因此构建这样的列表可能很棘手。这种方法在某些情况下可能会产生误报。
此外,颠倒某些字母的顺序可能会欺骗许多用户。可以使用 Jaro-Winkler 和 Levenshtein 距离等算法来检查变位词或非常相似的名称(即检查是否已经存在类似的 username/company 名称)。然而,有时,这可能是由于某些地区某些单词的拼写不同(例如,'centre' 与 'center'),或者某些公司的名称可能故意包含字谜。这种方法可能会进一步增加误报的数量。
此外,如 Jonathan 所述,清理也是一种好方法,但它可能无法防止字谜并给想要使用某些特殊字符的合法用户带来问题。
正如OP也提到的,特殊字符也可以被剥离。名称的其他部分也可能需要删除,例如 'Inc.'、'.com' 等常见名称
最后,可以将名称限制为仅包含一种语言的字符,而不是来自多种语言的字符的混合(更宽松的版本可能不允许在同一个词中混合字符 - 而如果以 space 分隔)。限制首字母大写,其余字母小写可以进一步改进这种方法,因为某些小写字母(如 'l')在某些情况下可能看起来像大写字母(如 'I')使用字体。排除使用某些符号(如“|”)将进一步增强这种方法。此解决方案将增加某些无法使用某些名称的用户的烦恼。
也可以结合使用 some/all 上述方法。方法的选择以及它们将如何应用(例如,您可以选择禁止相似的名称,或者在名称相似的情况下要求版主批准,或者不采取任何行动,而只是警告 moderator/administrator) 取决于您要解决的场景。
对于这个关于用户名的问题,我可能有一个创新的解决方案。显然,你希望允许 ASCII 字符,但在某些特殊情况下,将使用其他字符(不同语言,如你所说)。
我认为一种允许在用户名中同时使用 ASCII 和其他字符的直观方法,同时受到 "Unicode Vulnerabilities" 的保护,如下所示:
允许所有 ASCII 字符并禁止其他字符,除非用户名中有 x 或更多 这些特殊字符(用户名是另一种语言)。
举个例子:
Whatsapp, Inc + (U+180E) - 不允许,只有 1 个特殊字符。
элч + (U+180E) - 允许!它有 超过 x 个特殊字符(例如,3)。因为是蒙古文所以可以使用蒙古文分隔符。
显然,这并不能 100% 保护您免受此类漏洞的侵害,但这是我一直在使用的一种非常有效的方法,特别是如果您没有在 "login" 上提及此算法的存在或 "register" 页面,因为攻击者可能会发现您有一种算法可以保护网站免受此类攻击,但不要提及它,这样他们就无法对其进行逆向工程并找到绕过它的方法。
抱歉,如果这不是您正在寻找的答案,只是分享我的想法。
编辑:或者您可以使用 RNN(递归神经网络)AI 来检测语言并允许来自该语言的特定字符。
你说的是同形字攻击。
Unicode here, and also have a look at this. There should be libraries based on these or pontentially other databases. One such library is this one 有一个 "confusables" 列表,您可以在 Java 或 Java 脚本中使用。其他语言也必须存在同样的情况,或者您可以编写一个。
我认为重要的是不要拥有自己的数据库 - 图书馆或服务很容易在好的数据之上完成。
至于是否应该过滤掉外观相似的用户名 - 我认为这取决于情况。如果用户有兴趣尝试伪造彼此的用户名,也许是的。对于许多其他类型的数据,这样做可能没有意义。除了您应该使用数据点评估应用程序中的风险之外,我认为没有通用的最佳实践。
对于不同的问题也是一种不同的方法,但如果您的正则表达式引擎支持 Unicode,则通常适用于 Unicode 输入验证的是正则表达式中的 \w
单词字符。在这样的引擎中,\w
应该匹配单词字符的所有 Unicode 类,即。任何语言的字母、修饰符和连接符,但没有别的(没有特殊字符)。这不能防止同形文字攻击,但可以防止某些注入,同时保持您的应用程序对 Unicode 友好。
"Five things everyone should know about Unicode" 是一篇博客 post,展示了如何将 Unicode 字符用作网站的攻击媒介。
此类真实世界攻击的主要示例是提交到 Google Play 商店的虚假 WhatsApp 应用程序,在开发者名称中使用了不可打印的 unicode space,这使得名称独一无二并允许它通过 Google 的过滤器。蒙古元音分隔符 (U+180E) 就是这样一种不可打印的 space 字符。
另一个漏洞是使用看起来相似的替代 Unicode 字符。 Mimic 工具展示了它的工作原理。
我能想到的一个例子是在注册新用户时保护用户名。您不希望两个用户名相同或看起来相同。
你如何防止这种情况发生?那里有这些角色的列表吗?从所有表单输入中删除所有这些类型的字符是否应该成为一种常见的做法?
当您拥有已知安全值的白名单并排除所有其他值时,所有清理工作效果最佳。
ASCII 就是这样的一组字符。
这可以通过多种方式来解决,但是每一种方式都可能会增加误报的数量,从而引起合法用户的烦恼。此外,其中 none 将适用于 100% 的情况(即使合并)。他们只会添加一个额外的层。
一种方法是创建具有相似字符的表,并检查是否存在重复名称。 'look similar' 的含义在很多情况下是主观的,因此构建这样的列表可能很棘手。这种方法在某些情况下可能会产生误报。
此外,颠倒某些字母的顺序可能会欺骗许多用户。可以使用 Jaro-Winkler 和 Levenshtein 距离等算法来检查变位词或非常相似的名称(即检查是否已经存在类似的 username/company 名称)。然而,有时,这可能是由于某些地区某些单词的拼写不同(例如,'centre' 与 'center'),或者某些公司的名称可能故意包含字谜。这种方法可能会进一步增加误报的数量。
此外,如 Jonathan 所述,清理也是一种好方法,但它可能无法防止字谜并给想要使用某些特殊字符的合法用户带来问题。
正如OP也提到的,特殊字符也可以被剥离。名称的其他部分也可能需要删除,例如 'Inc.'、'.com' 等常见名称
最后,可以将名称限制为仅包含一种语言的字符,而不是来自多种语言的字符的混合(更宽松的版本可能不允许在同一个词中混合字符 - 而如果以 space 分隔)。限制首字母大写,其余字母小写可以进一步改进这种方法,因为某些小写字母(如 'l')在某些情况下可能看起来像大写字母(如 'I')使用字体。排除使用某些符号(如“|”)将进一步增强这种方法。此解决方案将增加某些无法使用某些名称的用户的烦恼。
也可以结合使用 some/all 上述方法。方法的选择以及它们将如何应用(例如,您可以选择禁止相似的名称,或者在名称相似的情况下要求版主批准,或者不采取任何行动,而只是警告 moderator/administrator) 取决于您要解决的场景。
对于这个关于用户名的问题,我可能有一个创新的解决方案。显然,你希望允许 ASCII 字符,但在某些特殊情况下,将使用其他字符(不同语言,如你所说)。
我认为一种允许在用户名中同时使用 ASCII 和其他字符的直观方法,同时受到 "Unicode Vulnerabilities" 的保护,如下所示:
允许所有 ASCII 字符并禁止其他字符,除非用户名中有 x 或更多 这些特殊字符(用户名是另一种语言)。
举个例子:
Whatsapp, Inc + (U+180E) - 不允许,只有 1 个特殊字符。
элч + (U+180E) - 允许!它有 超过 x 个特殊字符(例如,3)。因为是蒙古文所以可以使用蒙古文分隔符。
显然,这并不能 100% 保护您免受此类漏洞的侵害,但这是我一直在使用的一种非常有效的方法,特别是如果您没有在 "login" 上提及此算法的存在或 "register" 页面,因为攻击者可能会发现您有一种算法可以保护网站免受此类攻击,但不要提及它,这样他们就无法对其进行逆向工程并找到绕过它的方法。
抱歉,如果这不是您正在寻找的答案,只是分享我的想法。
编辑:或者您可以使用 RNN(递归神经网络)AI 来检测语言并允许来自该语言的特定字符。
你说的是同形字攻击。
Unicode here, and also have a look at this. There should be libraries based on these or pontentially other databases. One such library is this one 有一个 "confusables" 列表,您可以在 Java 或 Java 脚本中使用。其他语言也必须存在同样的情况,或者您可以编写一个。
我认为重要的是不要拥有自己的数据库 - 图书馆或服务很容易在好的数据之上完成。
至于是否应该过滤掉外观相似的用户名 - 我认为这取决于情况。如果用户有兴趣尝试伪造彼此的用户名,也许是的。对于许多其他类型的数据,这样做可能没有意义。除了您应该使用数据点评估应用程序中的风险之外,我认为没有通用的最佳实践。
对于不同的问题也是一种不同的方法,但如果您的正则表达式引擎支持 Unicode,则通常适用于 Unicode 输入验证的是正则表达式中的 \w
单词字符。在这样的引擎中,\w
应该匹配单词字符的所有 Unicode 类,即。任何语言的字母、修饰符和连接符,但没有别的(没有特殊字符)。这不能防止同形文字攻击,但可以防止某些注入,同时保持您的应用程序对 Unicode 友好。