C语言 sprintf/snprintf哪个更安全?

qmb5sa22  于 2023-04-11  发布在  其他
关注(0)|答案(7)|浏览(227)

我想知道这两个选项中哪一个更安全用途:

#define MAXLEN 255
char buff[MAXLEN + 1]
  1. sprintf(buff, "%.*s", MAXLEN, name)
  2. snprintf(buff, MAXLEN, "%s", name)
    我的理解是两者都是一样的。请建议。
bqf10yzr

bqf10yzr1#

你给出的两个表达式是 * 不 * 等价的:sprintf不接受指定要写入的最大字节数的参数;它只需要一个目标缓冲区,一个格式字符串和一堆参数。因此,它可能会写入比缓冲区空间更多的字节,并在这样做时写入任意代码。%.*s不是一个令人满意的解决方案,因为:
1.当格式说明符引用长度时,它引用的是strlen的等价物;这是字符串中字符数的度量,而不是它在内存中的长度(即它不计算空终止符)。
1.格式字符串的任何更改(例如添加换行符)都会改变sprintf版本在缓冲区溢出方面的行为。对于snprintf,无论格式字符串或输入类型如何更改,都会设置一个固定的明确最大值。

slsn1g29

slsn1g292#

最好和最灵活的方法是使用snprintf

size_t nbytes = snprintf(NULL, 0, "%s", name) + 1; /* +1 for the '\0' */
char *str = malloc(nbytes);
snprintf(str, nbytes, "%s", name);

在C99中,snprintf返回写入字符串的字节数(不包括'\0')。如果字节数少于所需的字节数,则snprintf返回扩展格式所需的字节数通过向snprintf传递一个长度为0的字符串,你可以提前知道扩展后的字符串有多长,并使用它来分配必要的内存。

xhv8bpkk

xhv8bpkk3#

就问题中的简单例子而言,两次通话的保安程度可能没有太大分别,但在一般情况下,snprintf()可能更安全。一旦你有一个更复杂的格式字符串,有多个转换规范,它可能会很困难(或几乎不可能),以确保在不同的转换中准确计算缓冲区长度-特别是因为以前的转换不一定会产生固定数量的输出字符。
所以,我会坚持使用snprintf()
snprintf()的另一个小优势(尽管与安全性无关)是它会告诉您需要多大的缓冲区。
最后要注意的是-你应该在snprintf()调用中指定实际的缓冲区大小-它会为你处理null终止符的解释:

snprintf(buff, sizeof(buff), "%s", name);
rsaldnfx

rsaldnfx4#

我会说snprintf()更好,直到我读到这段话:
https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/838-BSI.html
简短的总结是:snprintf()不可移植,它的行为会随着系统的不同而改变。当snprintf()仅仅通过调用sprintf()来实现时,snprintf()可能会出现最严重的问题。您可能认为它可以保护您免受缓冲区溢出的影响,从而放松警惕,但事实并非如此。
所以现在我仍然说snprintf()更安全,但在使用它时也要谨慎。

uyto3xhc

uyto3xhc5#

这两者之间有一个重要的区别--snprintf调用将扫描name参数到末尾(终止NUL),以找出正确的返回值。另一方面,sprintf调用将从name读取最多255个字符。
因此,如果name是一个指向非NUL终止的缓冲区的指针,至少有255个字符,则snprintf调用可能会在缓冲区的末尾运行并触发未定义的行为(例如崩溃),而sprintf版本则不会。

h22fl7wq

h22fl7wq6#

你的sprintf语句是正确的,但是我没有足够的自信来使用它来达到安全的目的(例如,缺少一个神秘的字符,你就没有屏蔽了),而周围有snprintf可以应用于任何格式...哦,等等 snprintf不在ANSI C 中。它是(只有?)C99。这可能是一个(弱)的理由来选择另一个。
你也可以用strncpy,对吧?
例如

char buffer[MAX_LENGTH+1];
  buffer[MAX_LENGTH]=0;             // just be safe in case name is too long
  strncpy(buffer,MAX_LENGTH,name);  // strncpy will never overwrite last byte
goqiplq2

goqiplq27#

两者都能给予你想要的结果,但是snprintf更通用,无论给定的格式是什么,它都能保护你的字符串不被溢出。
此外,由于snprintf(或sprintf)添加了最后一个\0,因此应该将字符串缓冲区大一个字节,即char buff[MAXLEN + 1]

相关问题