安全注意事项:国际功能
本主题提供有关与国际支持功能相关的安全注意事项的信息。 可以将它用作起点,然后查看相关国际技术的文档,了解特定于技术的安全注意事项。
本主题包含以下各节:
字符转换函数的安全注意事项
MultiByteToWideChar 和 WideCharToMultiByte 是最常用于在 ANSI 和 Unicode 之间转换字符的 Unicode 和字符集函数。 这些函数可能会导致安全风险,因为它们以不同的方式对输入和输出缓冲区的元素进行计数。 例如, MultiByteToWideChar 采用以字节为单位的输入缓冲区,并将转换后的字符放入以 Unicode 字符为单位的缓冲区中。 当应用程序使用此函数时,它必须正确调整缓冲区大小以避免缓冲区溢出。
WideCharToMultiByte 默认为代码页的“最佳拟合”映射,例如 1252。 但是,这种类型的映射允许同一字符串的多个表示形式,这可能会使应用程序容易受到攻击。 例如,带二元 (“Ä”) 的拉丁文大写字母 A 可能映射到拉丁文大写字母 A (“A”) ;亚洲语言中的 Unicode 字符可能映射到斜杠 (“/”) 。 从安全角度来看,首选使用 WC_NO_BEST_FIT_CHARS 标志。
某些代码页(例如,5022x (iso-2022-x) 代码页)本质上是不安全的,因为它们允许同一字符串的多个表示形式。 正确编写的代码以 Unicode 形式执行安全检查,但这些类型的代码页会扩展应用程序的易受攻击性,如果可能,应避免这样做。
比较函数的安全注意事项
字符串比较可能会带来安全问题。 由于所有比较函数略有不同,因此一个函数可能会报告两个字符串相等,而另一个函数可能会认为它们不同。 以下是应用程序可用于比较字符串的几个函数:
- lstrcmpi。 根据区域设置的规则比较两个字符串,不区分大小写。 函数通过相互检查第一个字符、第二个字符相互检查等方式来比较字符串,直到发现不相等或到达字符串的末尾。
- lstrcmp。 使用类似于 lstrcmpi 的技术比较字符串。 唯一的区别是 lstrcmp 执行区分大小写的字符串比较。
- CompareString、 CompareStringEx (Windows Vista 及更高版本) 。 对应用程序提供的区域设置执行字符串比较。 CompareStringEx 类似于 CompareString,但它按区域设置 名称 而不是 区域设置标识符来标识区域设置。 这些函数类似于 lstrcmpi 和 lstrcmp ,只不过它们在特定的区域设置而不是用户选择的区域设置上运行。
- CompareStringOrdinal (Windows Vista 及更高版本) 。 比较两个 Unicode 字符串以测试二进制等效性。 除了不区分大小写的选项外,此函数会忽略所有非二进制等效性,并测试所有码位是否相等,包括在语言 排序 方案中未给予任何权重的码位。 请注意,本主题中提到的其他比较函数不会测试所有码位是否相等。
- FindNLSString、 FindNLSStringEx (Windows Vista 及更高版本) 。 在另一个 Unicode 字符串中找到 Unicode 字符串。 FindNLSStringEx 类似于 FindNLSString,只不过它通过区域设置名称而不是区域设置标识符来标识区域设置。
- FindStringOrdinal (Windows 7 及更高版本) 。 在另一个 Unicode 字符串中找到一个 Unicode 字符串。 对于所有非语言比较,应用程序应使用此函数而不是 FindNLSString 。
与 lstrcmpi 和 lstrcmp 一样, CompareString 按字符计算字符串。 但是,许多语言都有多字符元素,例如,传统西班牙语中的双字符元素“CH”。 由于 CompareString 使用应用程序提供的区域设置来标识多字符元素,而 lstrcmpi 和 lstrcmp 使用线程区域设置,因此相同的字符串可能不会相等。
CompareString 忽略未定义的字符,因此返回零 (指示许多非常不同的字符串对) 相等的字符串。 字符串可能包含未映射到任何字符的值,也可能包含具有应用程序域外部语义的字符,例如 URL 中的控制字符。 使用此函数的应用程序应提供错误处理程序和测试字符串,以确保它们在使用前有效。
注意
对于 Windows Vista 及更高版本, CompareStringEx 类似于 CompareString。 这些函数的安全问题是相同的。
类似的安全问题适用于进行隐式比较的函数,如 FindNLSString。 根据设置的标志,调用 FindNLSString 以在另一个字符串中搜索一个字符串的结果可能会有很大不同。
注意
对于 Windows Vista 及更高版本, FindNLSStringEx 类似于 FindNLSString。 这些函数的安全问题是相同的。
文件名中字符集的安全注意事项
日语系统上使用的 Windows 代码页和 OEM 字符集包含日元符号 (¥) ,而不是反斜杠 (\) 。 因此,日元字符是 NTFS 和 FAT 文件系统的禁止字符。 将 Unicode 映射到日语代码页时,转换函数会将反斜杠 (U+005C) 和普通 Unicode Yen 符号 (U+00A5) 映射到此相同字符。 出于安全原因,应用程序通常不应允许 Unicode 字符串中的字符 U+00A5,该字符串可以转换为 FAT 文件名。
国际化域名的安全注意事项
) 的国际化域名 (IDN 由网络工作组 RFC 3490 指定:将应用程序中的域名国际化 (IDNA) 。 该标准引入了许多安全问题。
表示不同脚本中的某些字符的字形可能看起来相似甚至相同。 例如,在许多字体中,西里尔文小写字母 A (“a”) 与拉丁文小写字母 A (“a”) 无法区分。 无法直观地判断“example.com”和“example.com”是两个不同的域名,一个名称中带有拉丁文小写 A,另一个名称为西里尔文小写 A。肆无忌惮的主机站点可以使用这种视觉不明确性来假装是欺骗攻击中的另一个站点。
IDNA 允许用于 IDN 的扩展字符集在特定脚本中也有欺骗的可能性。 例如,连字符-减 (“-”U+002D) 之间有很强的相似性,连字符 (“—” U+2010) , 非中断连字符 (“-” U+2011) ,数字短划线 (“\u2012” U+2012) ,en 短划线 (“–” U+2013) ,减号 (“?”U+2212) 。
某些兼容性组合也出现了类似的问题。 例如,在转换为 Punycode 之前,将单个 Unicode 字符 NUMBER TWENTY FULL STOP (“20.”、U+249B) 转换为“20.” (U+0032 U+0030 U+0030 U+002E) 。 换句话说,此组合将插入句点 (完全停止) 。 这种组合具有欺骗潜力。
混合 IDN 中的不同脚本不一定表示欺骗或欺骗意图。 技术报告 #36:Unicode 安全注意事项 提供了包含混合脚本的合理 IDN 的几个示例,例如 XML-Документы.com (“Документы”是俄语的“documents”) 。
欺骗攻击不限于 IDN。 例如,“rnicrosoft.com”看起来很像“microsoft.com”,但它是 ASCII 名称。 此外,欺骗攻击可能通过名称的损坏进行。 在已知品牌名称后添加额外的标签,或在标记为安全的 URL 的路径中包含品牌名称可能会使新手用户感到困惑,而不管 IDN 的使用如何。 对于某些区域设置,IDN 是必需的,并且这些名称的 Punycode 格式是不能接受的,因为它会使名称看起来像胡言乱语。
有关此处提到的安全问题以及大量与 IDNA 相关的其他问题的详细信息,请参阅 技术报告 #36:Unicode 安全注意事项。 除了详细讨论 IDNA 相关的安全问题外,此报告还提供了有关在应用程序中处理可疑 IDN 的建议。
ANSI 函数的安全注意事项
注意
如果可能,建议在全球化应用程序中使用 Unicode,尤其是新应用程序。 仅当有替代不使用 Unicode 的原因时,才应使用 ANSI 函数,例如,符合不支持 Unicode 的旧协议。
许多国家/地区语言支持 (NLS) 函数(例如 GetLocaleInfo 和 GetCalendarInfo)具有特定的 ANSI 版本,在本例中分别为 GetLocaleInfoA 和 GetCalendarInfoA。 当应用程序使用具有基于 Unicode 的操作系统(如 Windows NT、Windows 2000、Windows XP 或 Windows Vista)的函数的 ANSI 版本时,该函数可能会失败或生成未定义的结果。 如果有令人信服的理由将 ANSI 函数用于此类操作系统,请确保应用程序传递的数据对 ANSI 有效。
Unicode 规范化的安全注意事项
由于 Unicode 规范化可以更改字符串的形式,因此通常应在规范化后实现安全机制或字符验证算法。 例如,假设某个应用程序具有接受文件名但不接受路径名称的 Web 界面。 全角 U+FF43 U+FF1A U+FF3C U+FF57 U+FF49 U+FF4E U+FF44 U+FF4F U+FF57 U+FF53 (c : \ w i n d o w s)
更改为 U+006 3 U+001A U+003C U+0077 U+0069 U+006E U+0064 U+006F U+0077 U+0073 (c:\windows)
,形式为 KC 规范化。 如果应用程序在实现规范化之前测试是否存在冒号和反斜杠字符,则结果可能是意外访问文件。
虽然 Unicode 规范化是确保操作系统安全的一个元素,但请记住,规范化不能替代全面的安全策略。
相关主题