strcat_如何避免缓冲区溢出问题?

strcat_如何避免缓冲区溢出问题?,c,C,我有下面一段代码 #include <stdio.h> #include <string.h> void fn(char *status, size_t maxLen) { strcat(status, "1234567890"); } int main() { char status[5] = { 0 }; size_t statusMaxLen = sizeof(status) / sizeof(status[0]); printf

我有下面一段代码

#include <stdio.h>
#include <string.h>

void fn(char *status, size_t maxLen)
{
    strcat(status, "1234567890");
}

int main()
{
    char status[5] = { 0 };
    size_t statusMaxLen = sizeof(status) / sizeof(status[0]);
    printf("%s%zu", "size of a status string ", statusMaxLen);
    fn(status, statusMaxLen);
    return 0;
}
得到

调试断言失败。缓冲区太小

所以,唯一的错误类型是不同的,但我的程序仍然崩溃。避免崩溃的解决方案是在连接之前检查大小。在这种情况下,为什么我需要strcat_。完成尺寸检查后,strcat也可以正常工作。那么,strcat_的真正用途是什么呢

无论我使用的是
strcat
还是
strcat\u
,我都需要在复制/连接之前检查大小。如果我做尺寸检查,那么为什么我更喜欢
strcat\s
而不是
strcat

if((strlen("1234567890") + strlen(status)) < maxLen){ 
    strcat(status, "1234567890");}`
if((strlen(“1234567890”)+strlen(status))
strcat()
对字符串进行操作。因此,缓冲区必须足够大,以容纳终止的
\0
。或者确保字符串小于缓冲区的大小。另外,请确保字符串末尾有一个
\0

另外,如果您阅读了strcat()
的文档,就会明白您提供的缓冲区太小,无法容纳生成的字符串
strcat()
不会分配内存以容纳更长的字符串


我现在无法测试,但您可能需要:

size_t statusMaxLen = sizeof(status) / sizeof(status[0]) - 1;

statusMaxLen
变小为1(需要
\0
)。

strcat_s()的优点是可以保证检测到此错误。使用
strcat()
,如果存在溢出,则行为未定义

见:

在运行时检测到以下错误,并调用当前安装的约束处理程序函数:

  • src或dest是空指针
  • destsz为零或大于RSIZE_MAX
  • dest的第一个destsz字节中没有空终止符
  • 将发生截断(dest末尾的可用空间不适合src的每个字符,包括空终止符)
  • 源字符串和目标字符串之间会发生重叠

strcat()
的定义清楚地提示了程序崩溃的原因:

它接受两个参数,即两个字符串或字符数组,并将结果连接字符串存储在参数中指定的第一个字符串中

您的第一个参数
status
不够大,无法容纳连接的字符串

strcat
将导致堆栈崩溃,
strcat
将导致segfault。这是两件不同的事情,如中所述:


无论使用哪个字符串连接函数,都应始终检查缓冲区大小。也就是说,使用strcat的代码在两个方面更好:

  • 这不再是缓冲区溢出漏洞

    当攻击者能够提供过长的数据时,就会出现缓冲区溢出漏洞,然后该数据会覆盖缓冲区之外的内容,在某些情况下,攻击者可以通过诱使进程运行恶意代码或以其他方式进行不当行为来控制进程

    由于strcat_s崩溃而不是允许这种情况发生,因此该行为现在是可预测的,攻击者无法利用

  • 您可以选择比破坏进程更有用的行为

    当strcat检测到目标缓冲区太小时,可以调用它

实际上没有办法检查缓冲区大小。即使您使用
strncat
,您也会遇到这样一个问题,即如果目标缓冲区太小,则
strncat
不会为null并终止它,这可能会导致各种问题。没关系,我把strncpy和strncat搞混了。请注意,
strncat
的size参数可能没有达到预期效果


无论我使用strcat还是strcat,我都需要在复制/连接之前检查大小。如果我做尺寸检查,为什么我更喜欢strcat_而不是strcat

你不应该。如果事先检查尺寸,
strcat
strcat
更快、更便携

\u
函数通常是危险的,因为它们标准化程度低,并且缺乏编译器支持

缓冲区溢出是很糟糕的,但是让程序崩溃并不是一个“优势”。相反,要确保它根本不会崩溃

在上一个示例中可能发生的最糟糕的情况是,
strlen
在传递过长或以非null结尾的字符串时继续读取越界,这将导致数组越界访问,并可能导致seg故障崩溃


根据经验,首先清理程序的输入,然后对已验证的数据应用尽可能快的函数。

strcat()
溢出缓冲区,因为它不会检查以确保传递的参数正确,因为在C中无法知道传递给函数的数组的大小
strcat_s()
避免缓冲区溢出的方法与可移植的标准C函数
strncat()
避免缓冲区溢出的方法相同:将要复制的最大长度传递给函数,这样就不会覆盖缓冲区
strcat\u s()
strncat()
@andre相比没有任何优势。无论我使用strcat还是strcat,我都需要在复制/连接之前检查大小。如果我做尺寸检查,为什么我更喜欢strcat_而不是strcat?你并不总是第一次撞车。当你没有崩溃,黑客可以接管你的电脑。但是你总是会遇到第二次崩溃。因为没有人回答你的问题,你是对的。只要ypu正确执行检查,对strcat_s没有任何好处。从避免程序崩溃的意义上讲,这是不安全的。事实上,故意破坏你的程序是安全的。缓冲区溢出是高度爆炸性的
size_t statusMaxLen = sizeof(status) / sizeof(status[0]) - 1;