CRT 中的安全功能
许多旧 CRT 函数具有更新、更安全的版本。 如果存在安全函数,则较旧的、安全性更低的版本将标记为已弃用。 新版本具有 _s
(“secure”)后缀。
在此上下文中,“已弃用”意味着不建议使用该函数。 这并不意味着函数将从 CRT 中删除。
安全函数不会阻止或更正安全错误。 相反,它们会在发生错误时捕获错误。 它们对错误条件进行额外的检查。 如果出现错误,则调用错误处理程序(请参阅参数验证)。
例如,函数 strcpy
无法判断正在复制的字符串对于目标缓冲区而言是否太大。 其安全对应项 strcpy_s
会将缓冲区大小作为参数。 因此,可以确定是否会发生缓冲区溢出。 如果你使用 strcpy_s
将 11 个字符复制到 10 个字符缓冲区中,则这是你方造成的错误;strcpy_s
无法更正错误。 但它可以通过调用无效的参数处理程序来检测错误并通知你。
消除弃用警告
可通过多种方式消除针对较旧的、安全性更低的函数的弃用警告。 最简单的方法是定义 _CRT_SECURE_NO_WARNINGS
或使用 warning
pragma。 这将禁用弃用警告,但导致出现警告的安全问题仍存在。 更佳的做法是,将弃用警告保持启用状态并利用新的 CRT 安全功能。
在 C++ 中,消除弃用警告的最简单方法是使用安全模板重载。 在许多情况下,重载会消除弃用警告。 它们会将对已弃用函数的调用替换为对安全版本的函数的调用。 例如,考虑此对 strcpy
的已弃用调用:
char szBuf[10];
strcpy(szBuf, "test"); // warning: deprecated
将 _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
定义为 1 可通过将 strcpy
调用更改为 strcpy_s
(这将阻止缓冲区溢出)来消除警告。 有关详细信息,请参阅安全模板重载。
对于那些不带安全模板重载的已弃用的函数,你应考虑手动更新代码以使用安全版本。
弃用警告的另一个源(与安全性无关)为 POSIX 函数。 将 POSIX 函数名称替换为其标准等效项(例如,将 access
更改为 _access
),或者通过定义 _CRT_NONSTDC_NO_WARNINGS
来禁用与 POSIX 相关的弃用警告。 有关详细信息,请参阅兼容性。
更多安全功能
一些安全功能包括:
参数验证
安全函数及其许多不安全的对应函数会验证参数。 验证可能包括:
- 检查
NULL
值。 - 检查枚举值的有效性。
- 检查整数值是否在有效范围内。
有关详细信息,请参阅参数验证。
开发人员也可访问无效参数的处理程序。 当函数遇到无效参数时,CRT 允许通过
_set_invalid_parameter_handler
或_set_thread_local_invalid_parameter_handler
检查这些问题,而不是断言和退出应用程序。- 检查
调整大小的缓冲区
必须将缓冲区大小传递给写入缓冲区的任何安全函数。 安全版本在写入之前会验证缓冲区是否足够大。 验证有助于避免危险的缓冲区溢出错误,这些错误可能允许恶意代码执行。 这些函数通常返回一个
errno
错误代码并调用无效参数处理程序(如果缓冲区太小)。 从输入缓冲区读取的函数(如gets
)具有需要您指定最大大小的安全版本。null 终止
某些可能保留非终止字符串的函数具有安全版本,这将确保字符串以 null 结束。
增强型错误报告
安全函数将返回错误代码以及比先前存在的函数返回的错误信息更多的错误信息。 安全函数和许多先前存在的函数现在可设置
errno
,并且通常会返回errno
代码类型,以便提供更好的错误报告。文件系统安全
默认情况下,安全文件 I/O API 支持安全文件访问。
Windows 安全性
安全进程 API 强制安全策略并允许指定 ACL。
格式字符串语法检查
例如,在
printf
格式字符串中使用不正确的类型字段字符时,检测到无效字符串。