Arp*_*pit 40 c unix security printf secure-coding
我想知道这两个选项中哪一个更安全:
#define MAXLEN 255
char buff[MAXLEN + 1]
Run Code Online (Sandbox Code Playgroud)
sprintf(buff, "%.*s", MAXLEN, name)
snprintf(buff, MAXLEN, "%s", name)
我的理解是两者都是一样的.请建议.
aze*_*nik 35
你给出的两个表达式不等价:sprintf没有参数指定要写入的最大字节数; 它只需要一个目标缓冲区,一个格式字符串和一堆参数.因此,它可能会写入比缓冲区空间更多的字节,并且这样写入任意代码.这%.*s不是一个满意的解决方案,因为:
strlen; 这是字符串中字符数的度量,而不是内存中的长度(即它不计算空终止符).sprintf版本相对于缓冲区溢出的行为.使用时snprintf,无论格式字符串或输入类型如何变化,都会设置固定的清除最大值.Mic*_*urr 11
对于问题中的简单示例,两个调用之间的安全性可能没有太大差异.但是,在一般情况下snprintf()可能更安全.一旦你有一个具有多个转换规范的更复杂的格式字符串,就很难(或几乎不可能)确保在不同的转换中准确计算缓冲区长度 - 特别是因为之前的转换不一定产生固定数字输出字符.
所以,我坚持下去snprintf().
另一个小优势snprintf()(虽然不是安全相关)是它会告诉你需要多大的缓冲区.
最后一点 - 你应该在snprintf()调用中指定实际的缓冲区大小- 它将为你处理空终止符的计算:
snprintf(buff, sizeof(buff), "%s", name);
Run Code Online (Sandbox Code Playgroud)
最好和最灵活的方法是使用snprintf!
size_t nbytes = snprintf(NULL, 0, "%s", name) + 1; /* +1 for the '\0' */
char *str = malloc(nbytes);
snprintf(str, nbytes, "%s", name);
Run Code Online (Sandbox Code Playgroud)
在 C99 中,snprintf返回写入字符串的字节数,不包括'\0'. 如果少于所需的字节数,则snprintf返回扩展格式所需的字节数(仍不包括'\0')。通过传递snprintf一个长度为 0 的字符串,您可以提前找出扩展字符串的长度,并使用它来分配必要的内存。
snprintf()在我读这篇文章之前,我会说要好得多:
https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/838-BSI.html
简短的总结是:snprintf()不可移动其行为从系统变为系统.最严重的问题snprintf()时,可能发生snprintf()通过调用简单地实现sprintf().你可能认为它可以保护你免受缓冲区溢出和放松警惕,但也可能不是.
所以现在我仍然说snprintf()更安全,但在使用它时也要谨慎.
这两者之间有一个重要的区别——snprintf调用将扫描name参数到底(终止 NUL),以便找出正确的返回值。sprintf另一方面,该调用将从 中读取最多 255 个字符name。
因此,如果name是指向至少包含 255 个字符的非 NUL 终止缓冲区的指针,则snprintf调用可能会超出缓冲区末尾并触发未定义的行为(例如崩溃),而版本则sprintf不会。
Eli*_*ser -1
两者都会给出您想要的结果,但snprintf更通用,并且无论给出的格式字符串如何,都会保护您的字符串免遭溢出。
此外,因为snprintf(或sprintf就此而言)添加了一个final \0,您应该使字符串缓冲区大一个字节,char buff[MAXLEN + 1].