你的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
7条答案
按热度按时间bqf10yzr1#
你给出的两个表达式是 * 不 * 等价的:
sprintf
不接受指定要写入的最大字节数的参数;它只需要一个目标缓冲区,一个格式字符串和一堆参数。因此,它可能会写入比缓冲区空间更多的字节,并在这样做时写入任意代码。%.*s
不是一个令人满意的解决方案,因为:1.当格式说明符引用长度时,它引用的是
strlen
的等价物;这是字符串中字符数的度量,而不是它在内存中的长度(即它不计算空终止符)。1.格式字符串的任何更改(例如添加换行符)都会改变
sprintf
版本在缓冲区溢出方面的行为。对于snprintf
,无论格式字符串或输入类型如何更改,都会设置一个固定的明确最大值。slsn1g292#
最好和最灵活的方法是使用
snprintf
!在C99中,
snprintf
返回写入字符串的字节数(不包括'\0'
)。如果字节数少于所需的字节数,则snprintf
返回扩展格式所需的字节数通过向snprintf
传递一个长度为0的字符串,你可以提前知道扩展后的字符串有多长,并使用它来分配必要的内存。xhv8bpkk3#
就问题中的简单例子而言,两次通话的保安程度可能没有太大分别,但在一般情况下,
snprintf()
可能更安全。一旦你有一个更复杂的格式字符串,有多个转换规范,它可能会很困难(或几乎不可能),以确保在不同的转换中准确计算缓冲区长度-特别是因为以前的转换不一定会产生固定数量的输出字符。所以,我会坚持使用
snprintf()
。snprintf()
的另一个小优势(尽管与安全性无关)是它会告诉您需要多大的缓冲区。最后要注意的是-你应该在
snprintf()
调用中指定实际的缓冲区大小-它会为你处理null终止符的解释:rsaldnfx4#
我会说
snprintf()
更好,直到我读到这段话:https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/838-BSI.html
简短的总结是:
snprintf()
不可移植,它的行为会随着系统的不同而改变。当snprintf()
仅仅通过调用sprintf()
来实现时,snprintf()
可能会出现最严重的问题。您可能认为它可以保护您免受缓冲区溢出的影响,从而放松警惕,但事实并非如此。所以现在我仍然说
snprintf()
更安全,但在使用它时也要谨慎。uyto3xhc5#
这两者之间有一个重要的区别--
snprintf
调用将扫描name
参数到末尾(终止NUL),以找出正确的返回值。另一方面,sprintf
调用将从name
读取最多255个字符。因此,如果
name
是一个指向非NUL终止的缓冲区的指针,至少有255个字符,则snprintf
调用可能会在缓冲区的末尾运行并触发未定义的行为(例如崩溃),而sprintf
版本则不会。h22fl7wq6#
你的sprintf语句是正确的,但是我没有足够的自信来使用它来达到安全的目的(例如,缺少一个神秘的字符,你就没有屏蔽了),而周围有snprintf可以应用于任何格式...哦,等等 snprintf不在ANSI C 中。它是(只有?)C99。这可能是一个(弱)的理由来选择另一个。
你也可以用
strncpy
,对吧?例如
goqiplq27#
两者都能给予你想要的结果,但是
snprintf
更通用,无论给定的格式是什么,它都能保护你的字符串不被溢出。此外,由于
snprintf
(或sprintf
)添加了最后一个\0
,因此应该将字符串缓冲区大一个字节,即char buff[MAXLEN + 1]
。