我正在读一本关于计算机/加密等的书。通常作者使用strncpy(dest, src, strlen(src));
而不是strcpy(dest, src);
这样的东西对我来说没什么意义..好吧,我是一个专业程序员。
问题是:它真的有区别吗?真正的应用程序使用这样的东西?
答案 0 :(得分:13)
作者几乎肯定会滥用strn*
函数。不幸的是,几乎没有充分的理由使用strn*
函数,因为它们实际上并不是你想要的。
我们来看看strcpy
和strncpy
:
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
strcpy
功能会将src
复制到dest
,包括尾随\0
。它很少有用:
除非您知道源字符串适合目标缓冲区,否则会出现缓冲区溢出。缓冲区溢出会带来安全隐患,它们可能会导致程序崩溃,导致程序运行不正常。
如果您 知道源字符串和目标缓冲区的大小,您也可以使用memcpy
。
相比之下,strncpy
最多n
个src
字节复制到dest
,然后用\0
填充其余部分。它很少有用:
除非您知道源字符串小于目标缓冲区,否则您无法确定生成的缓冲区是否为空终止。如果您认为结果是以空值终止的,那么这可能会导致程序中其他地方出错。
如果您确实知道源字符串较小,那么您也可以使用memcpy
。
您可以在致电strncpy
后终止字符串,但是您确定要静默截断结果吗?我想大多数时候,你宁愿有错误信息。
strcpy
功能偶尔会很方便,但它主要是一个人们不太关心验证输入的时代的遗物。提供一个对于程序来说太大的字符串会使它崩溃,并且建议是“不要这样做”。
当您想要在固定大小的字段中传输数据时,strncpy
函数非常有用,并且您不希望将垃圾放在字段的其余部分中。这主要是人们使用固定大小字段的时代遗留物。
因此,您很少会在现代C软件中看到strcat
或strncpy
。
然而,你的例子结合了两个世界中最糟糕的。让我们来看看这段源代码:
strncpy(dest, src, strlen(src));
这会将src
复制到dest
,不带一个\0
终止符,不带边界检查。它结合了strcpy
(无边界检查)的最差方面与strncpy
的最差方面(无终结符)。如果您看到这样的代码,请逃跑。
好的C代码通常使用一些选项来处理字符串:
使用固定缓冲区和snprintf
,只要您不介意修复缓冲区。
使用有限字符串函数,例如strlcpy
和strlcat
。这些是BSD扩展。
使用跟踪字符串长度的自定义字符串点,并使用memcpy
和malloc
编写自己的函数。
答案 1 :(得分:1)
如果该代码是书中的逐字副本,则作者要么不知道C,要么不是安全专家,或者两者都不知道。
也可能是他使用了错误配置的编译器,明确禁止使用某些已知可能不安全的函数。当编译器无法区分安全和不安全以及潜在的不安全时,这是一个值得怀疑的做法,并且只是一直在阻碍。
答案 2 :(得分:0)
strn系列的原因是为了防止溢出缓冲区。如果您从调用者传递数据并盲目地相信它已正确地以空值终止并且不会溢出您正在复制它的缓冲区,那么您将被缓冲区溢出攻击所拥有。
效率差异可以忽略不计。 strn系列可能略微较慢,因为它需要继续检查您是否没有溢出。
答案 3 :(得分:0)
strncpy(dest,src,strlen(src));与strcpy(dest,src)相同;所以这里没有区别,但是..
Strcpy会导致安全漏洞,因为您不知道字符串有多长。聪明的人可以使用此功能覆盖服务器上的某些内容。
答案 4 :(得分:0)
对strcpy使用strncpy与其执行速度无关,但strncpy强烈降低了缓冲区溢出攻击的可能性。 在C中,指针是最强大的,但它们也使系统易受攻击。
摘好一本好的Hack-Proofing书可能对你有所帮助。
许多溢出错误是错误的字符串操作的结果。电话如 strcpy()在复制之前不检查字符串的长度。结果是 可能会发生缓冲区溢出。预计NULL终结符会 出席。从某种意义上说,攻击者依赖这个bug来利用 机;但是,这也意味着攻击者的注入缓冲区也必须 没有NULL字符。如果攻击者插入一个NULL字符,那么 字符串副本将在插入整个有效负载之前终止。