安全注意事项:Windows 用户界面

本主题提供有关 Windows 用户界面中安全注意事项的信息。 本主题不提供所有需要了解的安全问题。 相反,请将其用作此技术领域的起点和参考。

随着计算机互连的增加,开发人员现在必须关注应用程序安全性。 但是,安全性还增强了常规应用程序安全性和稳定性;因此,开发人员可以提供良好的用户体验是另一种方法。 以下主题讨论使用 Windows 用户界面时的一些潜在安全问题。

字符串注意事项

许多函数、消息和宏在其参数中使用字符串。 但是,通常不会检查字符串是否为 null 终止或长度。 相关的问题在于错误地计算字符串或缓冲区的长度。 在任一情况下,这都可能导致缓冲区溢出或数据截断,这可能会影响应用程序。 有关缓冲区溢出和其他安全问题的详细信息,请参阅 Microsoft Press Microsoft Michael Howard 和 David Leblanc 编写安全代码

若要以安全方式处理字符串,应执行以下作:

  • 根据情况检查字符串是否为 null 终止或适当的长度。
  • 请特别注意确定字符串或缓冲区的长度,尤其是在包含 TCHAR 值时。
  • 如果创建字符串或使用以前使用的字符串,请根据需要将其初始化为零或插入 null 终止符。

此外,请考虑在处理字符串时使用 StrSafe 函数。 这些函数旨在安全地处理字符串。

用户输入

Windows 用户界面涉及从用户获取和响应信息。 但是,输入不正确的数据的用户可能会中断应用程序,无论他们是否打算这样做。 因此,基数规则是必须验证所有输入。

主要关注的是字符串数据,字符串注意事项中讨论。 但是,在应用程序使用之前,应先验证所有类型的输入。 另一个问题是,当数据在一个时间点进行验证,但在使用数据之前发生更改,例如,在接收提供文本长度的消息时。 因此,如果数据有可能更改,则应在使用它之前检查数据

安全警报

下表列出了在未正确使用的情况下可能会损害应用程序安全性的功能。

特征 缓解
GetAtomName 指定缓冲区的大小时请小心。
GlobalGetAtomName 全局字符串原子可供任何应用程序访问。 但是,如果另一个应用程序不小心,它可能会错误处理其引用计数并删除它们。 应考虑改用全局整数原子。
ImpersonateDdeClientWindow 如果函数失败,则后续客户端请求是在调用过程的安全上下文中进行的。 如果调用进程作为高特权帐户运行,则这可能是个问题。 因此,如果调用失败或引发错误,则不会继续执行客户端请求。
DdeImpersonateClient 如果函数失败,则后续客户端请求是在调用过程的安全上下文中进行的。 如果调用进程作为高特权帐户运行,则这可能是个问题。 因此,如果调用失败或引发错误,则不会继续执行客户端请求。
GetClipboardFormatName 错误计算 lpszFormatName 缓冲区的大小,尤其是在 ANSI 和 Unicode 版本中使用应用程序时,可能会导致缓冲区溢出。 此外,请注意,如果字符串的长度超过 cchMaxCount 参数,则会截断该字符串,这可能会导致信息丢失。
GetMenuString lpString 参数是 TCHAR 缓冲区,nMaxCountTCHARs 中的菜单字符串长度。 错误地调整这些参数的大小是菜单字符串的长度(以字符为单位)。 正确调整这些参数的大小可能会导致字符串截断,从而导致数据丢失。
GetStringTypeAGetStringTypeExGetStringTypeW 若要避免缓冲区溢出,请正确设置 lpCharType 缓冲区的大小。
LoadLibrary 使用 LoadLibrary 加载错误的 DLL 可能会损害应用程序的安全性。
LoadString 不正确的使用包括指定 nBufferMax 参数中的错误大小。 例如,sizeof(lpBuffer) 提供缓冲区的大小(以字节为单位),这可能导致函数的 Unicode 版本的缓冲区溢出。 缓冲区溢出情况是应用程序中出现许多安全问题的原因。 在本例中,使用 sizeof(lpBuffer)/sizeof(TCHAR) 提供适当的缓冲区大小。
lstrcat 此函数使用结构化异常处理(SEH)捕获访问冲突和其他错误。 当此函数捕获 SEH 错误时,它将返回 NULL,不终止字符串,不返回 NULL 且不终止 null 且不通知调用方错误。 调用方无法安全地假定空间不足是错误条件。 第一个参数(lpString1)必须足够大,才能容纳 lpString2 和结束“\0”,否则可能会出现缓冲区溢出。 如果发生访问冲突,缓冲区溢出可能会导致对应用程序的拒绝服务攻击。 在最坏的情况下,缓冲区溢出可能会允许攻击者将可执行代码注入进程,尤其是在 lpString1 是基于堆栈的缓冲区时。 请考虑使用以下替代方法之一。 StringCbCatStringCchCat
lstrcpy 此函数使用结构化异常处理(SEH)捕获访问冲突和其他错误。 当此函数捕获 SEH 错误时,它将返回 NULL,不终止字符串,不返回 NULL 且不终止 null 且不通知调用方错误。 调用方无法安全地假定空间不足是错误条件。 第一个参数(lpString1)必须足够大,才能容纳 lpString2 和结束“\0”,否则可能会出现缓冲区溢出。 如果发生访问冲突,缓冲区溢出可能会导致对应用程序的拒绝服务攻击。 在最坏的情况下,缓冲区溢出可能会允许攻击者将可执行代码注入进程,尤其是在 lpString1 是基于堆栈的缓冲区时。 请考虑改用 StringCchCopy
lstrcpyn 此函数使用结构化异常处理(SEH)捕获访问冲突和其他错误。 当此函数捕获 SEH 错误时,它将返回 NULL,不终止字符串,不返回 NULL 且不终止 null 且不通知调用方错误。 调用方无法安全地假定空间不足是错误条件。 如果 lpString1 不足以包含复制的字符串,则可能会出现缓冲区溢出。 此外,复制整个字符串时,请注意,sizeof 返回字节数,而不是 WCHARsizeof 返回字节数而不是字符数,这对于此函数的 Unicode 版本不正确。 如果发生访问冲突,缓冲区溢出可能会对应用程序造成拒绝服务攻击。 在最坏的情况下,缓冲区溢出可能会允许攻击者将可执行代码注入进程,尤其是在 lpString1 是基于堆栈的缓冲区时。 请考虑改用 StringCchCopy
lstrlen lstrlen 假定 lpString 是一个以 null 结尾的字符串。 如果不是,这可能会导致缓冲区溢出或拒绝对应用程序的服务攻击。 请考虑使用以下替代方法之一。 StringCbLengthStringCchLength
wsprintf lpOut 中返回的字符串不能保证为 null 终止。 此外,请避免 %s 格式,这可能会导致缓冲区溢出。 如果发生访问冲突,则会导致针对应用程序拒绝服务。 在更糟的情况下,攻击者可以注入可执行代码。 请考虑使用以下替代方法之一。 StringCbPrintfStringCbPrintfExStringCbVPrintfStringCbVPrintfExStringCchPrintfStringCchPrintfExStringCchVPrintfStringCchVPrintfEx
wvsprintf lpOutput 中返回的字符串不能保证为 null 终止。 此外,请避免使用 %s 格式,这可能会导致缓冲区溢出。 如果服务导致访问冲突,则可能会导致拒绝服务,或者攻击者可能会注入可执行代码。 请考虑使用以下替代方法之一。 StringCbPrintfStringCbPrintfExStringCbVPrintfStringCbVPrintfExStringCchPrintfStringCchPrintfExStringCchVPrintfStringCchVPrintfEx

 

Microsoft安全

安全和标识

安全作方法索引

Microsoft安全响应中心

安全 API 最佳做法