安全注意事项:Windows 用户界面
本主题提供有关 Windows 用户界面中的安全注意事项的信息。 本主题只提供部分需要了解的安全问题。 相反,请将其用作该技术领域的起点和参考。
随着计算机互连性的增强,开发人员现在必须关注应用程序安全性。 然而,安全性也增强了一般应用程序的安全性和可靠性;因此,这是开发人员提供良好用户体验的另一种方式。 以下主题讨论使用 Windows 用户界面时的一些潜在安全问题。
字符串注意事项
许多函数、消息和宏在其参数中都会使用字符串。 但通常不会检查字符串的 null 终止字符或长度。 一个相关的问题是,错误计算字符串或缓冲区的长度。 无论哪种情况,这都可能导致缓冲区溢出或数据被截断,从而对你的应用程序产生不利影响。 有关缓冲区溢出和其他安全问题的详细信息,请参阅编写安全代码,作者:Michael Howard 和 David Leblanc,Microsoft Press,2002 年。
若要以安全方式处理字符串,应执行以下操作:
- 根据需要检查字符串的 null 终止字符或长度是否正确。
- 确定字符串或缓冲区的长度时要特别小心,尤其是当它包含 TCHAR 值时。
- 如果要创建字符串或使用以前使用过的字符串,请将其初始化为零或根据需要插入 null 终止符。
此外,处理字符串时请考虑使用 StrSafe 函数。 这些函数旨在安全地处理字符串。
用户输入
Windows 用户界面涉及获取和响应用户输入的信息。 但如果用户输入错误数据,则可能会破坏你的应用程序,无论他们是否有意这样做。 因此,基本规则是所有输入都必须经过验证。
字符串数据应为主要关注内容,这在字符串注意事项中进行了讨论。 然而,所有类型的输入在被应用程序使用之前都应经过验证。 另一个问题是,数据在某个时间点经过验证但在使用之前发生更改,例如,接收给出文本长度的消息时。 因此,如果数据有可能发生更改,应在使用数据之前对其进行检查。
安全警报
下表列出了如果使用不当可能会危及应用程序安全性的功能。
功能 | 缓解 |
---|---|
GetAtomName | 指定缓冲区的大小时请小心。 |
GlobalGetAtomName | 全局字符串原子可供任何应用程序访问。 但是,如果另一个应用程序不小心,它可能会错误地处理它们的引用计数并删除它们。 应考虑使用全局整数原子。 |
ImpersonateDdeClientWindow | 如果此函数失败,则后续客户端请求将在调用进程的安全上下文中发出。 如果调用进程作为高特权帐户运行,这可能会出现问题。 因此,如果调用失败或引发错误,请不要继续执行客户端请求。 |
DdeImpersonateClient | 如果此函数失败,则后续客户端请求将在调用进程的安全上下文中发出。 如果调用进程作为高特权帐户运行,这可能会出现问题。 因此,如果调用失败或引发错误,请不要继续执行客户端请求。 |
GetClipboardFormatName | 错误计算 lpszFormatName 缓冲区的正确大小,尤其是当应用程序同时用于 ANSI 和 Unicode 版本时,可能会导致缓冲区溢出。 另请注意,如果字符串比 cchMaxCount 参数长,则会被截断,这可能会导致信息丢失。 |
GetMenuString | lpString 参数是 TCHAR 缓冲区,nMaxCount 是 TCHAR 中菜单字符串的长度。 错误地调整这些参数的大小可能生成菜单字符串的字符长度。 错误地调整这些参数的大小可能会导致字符串被截断,从而可能导致数据丢失。 |
GetStringTypeA、GetStringTypeEx、GetStringTypeW | 为了避免缓冲区溢出,请正确设置 lpCharType 缓冲区的大小。 |
LoadLibrary | 错误地使用 LoadLibrary 可能会加载错误的 DLL,从而影响应用程序的安全性。 |
LoadString | 不正确的使用包括在 nBufferMax 参数中指定错误的大小。 例如,sizeof(lpBuffer) 指定缓冲区的大小(以字节为单位),这可能会导致该函数的 Unicode 版本发生缓冲区溢出。 缓冲区溢出情况是应用程序中许多安全问题的原因。 在这种情况下,使用 sizeof(lpBuffer)/sizeof(TCHAR) 可提供缓冲区的正确大小。 |
lstrcat | 此函数使用结构化异常处理 (SEH) 来捕获访问冲突和其他错误。 当此函数捕获 SEH 错误时,它会返回 NULL,而不以 null 终止字符串,以及不返回 NULL,不以 null 终止字符串,并且不通知调用方错误。 调用方如果假设空间不足是错误条件,就不安全。 第一个参数 lpString1 必须足够大以容纳 lpString2 和结尾的“\0”,否则可能会发生缓冲区溢出。 如果发生访问冲突,缓冲区溢出可能会导致针对应用程序的拒绝服务攻击。 在最坏的情况下,缓冲区溢出可能允许攻击者将可执行代码注入到你的进程中,特别是当 lpString1 是基于堆栈的缓冲区时。 请考虑使用以下替代方法之一。 StringCbCat 或 StringCchCat。 |
lstrcpy | 此函数使用结构化异常处理 (SEH) 来捕获访问冲突和其他错误。 当此函数捕获 SEH 错误时,它会返回 NULL,而不以 null 终止字符串,以及不返回 NULL,不以 null 终止字符串,并且不通知调用方错误。 调用方如果假设空间不足是错误条件,就不安全。 第一个参数 lpString1 必须足够大以容纳 lpString2 和结尾的“\0”,否则可能会发生缓冲区溢出。 如果发生访问冲突,缓冲区溢出可能会导致针对应用程序的拒绝服务攻击。 在最坏的情况下,缓冲区溢出可能允许攻击者将可执行代码注入到你的进程中,特别是当 lpString1 是基于堆栈的缓冲区时。 请考虑改用 StringCchCopy。 |
lstrcpyn | 此函数使用结构化异常处理 (SEH) 来捕获访问冲突和其他错误。 当此函数捕获 SEH 错误时,它会返回 NULL,而不以 null 终止字符串,以及不返回 NULL,不以 null 终止字符串,并且不通知调用方错误。 调用方如果假设空间不足是错误条件,就不安全。 如果 lpString1 不够大,无法容纳复制的字符串,则可能会发生缓冲区溢出。 另外,在复制整个字符串时,请注意 sizeof 返回字节数而不是 WCHAR,sizeof 返回字节数而不是字符数,这对于该函数的 Unicode 版本是不正确的。 如果发生访问冲突,缓冲区溢出可能会导致针对应用程序的拒绝服务攻击。 在最坏的情况下,缓冲区溢出可能允许攻击者将可执行代码注入到你的进程中,特别是当 lpString1 是基于堆栈的缓冲区时。 请考虑改用 StringCchCopy。 |
lstrlen | lstrlen 假定 lpString 是一个以 null 结尾的字符串。 如果不是,这可能会导致缓冲区溢出或针对你的应用程序的拒绝服务攻击。 请考虑使用以下替代方法之一。 StringCbLength 或 StringCchLength。 |
wsprintf | lpOut 中返回的字符串不保证以 null 终止。 另外,请避免使用 %s 格式,这可能导致缓冲区溢出。 如果发生访问冲突,则会导致针对你的应用程序的拒绝服务攻击。 在最糟糕的情况下,攻击者可能会注入可执行代码。 请考虑使用以下替代方法之一。 StringCbPrintf、StringCbPrintfEx、StringCbVPrintf、StringCbVPrintfEx、StringCchPrintf、StringCchPrintfEx、StringCchVPrintf 或 StringCchVPrintfEx。 |
wvsprintf | lpOutput 中返回的字符串不保证以 null 终止。 另外,请避免使用 %s 格式,这可能导致缓冲区溢出。 如果导致访问冲突,则可能导致拒绝服务攻击,或者攻击者可能会注入可执行代码。 请考虑使用以下替代方法之一。 StringCbPrintf、StringCbPrintfEx、StringCbVPrintf、StringCbVPrintfEx、StringCchPrintf、StringCchPrintfEx、StringCchVPrintf 或 StringCchVPrintfEx。 |
相关主题
-
Microsoft Security Response Center(Microsoft 安全响应中心)