我正在读一本关于计算机/密码学等的书。而且作者经常使用诸如此类的东西strncpy(dest, src, strlen(src));
代替strcpy(dest, src);
它对我来说没有多大意义。嗯,我是一名专业程序员。
问题是:它真的有真正的不同吗?真正的应用程序使用这样的东西?
我正在读一本关于计算机/密码学等的书。而且作者经常使用诸如此类的东西strncpy(dest, src, strlen(src));
代替strcpy(dest, src);
它对我来说没有多大意义。嗯,我是一名专业程序员。
问题是:它真的有真正的不同吗?真正的应用程序使用这样的东西?
作者几乎可以肯定是在滥用这些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
最多复制 in 的字节n
,然后用. 它很少有用:src
dest
\0
除非您知道源字符串小于目标缓冲区,否则您无法确定生成的缓冲区是否会被 nul 终止。如果您假设结果是 nul 终止的,这可能会导致程序中的其他地方出错。
如果您确实知道源字符串更小,那么您不妨再次使用memcpy
.
您可以在调用后简单地终止字符串strncpy
,但您确定要静默截断结果吗?我想大多数时候,您宁愿收到一条错误消息。
该strcpy
功能偶尔会很方便,但它主要是人们不太关心验证输入的时代的遗物。为程序提供太大的字符串会使程序崩溃,建议是“不要那样做”。
strncpy
当您想在固定大小的字段中传输数据并且不想在字段的其余部分中放置垃圾时,该功能很有用。这主要是人们使用固定大小字段的时代的遗迹。
所以你很少会在现代 C 软件中看到strcat
或。strncpy
但是,您的示例结合了两全其美。让我们检查一下这段源代码:
strncpy(dest, src, strlen(src));
这将复制src
到dest
中,没有\0
终止符,也没有边界检查。它将strcpy
(无边界检查)的最坏方面与strncpy
(无终止符)的最坏方面结合在一起。如果您看到这样的代码,请逃跑。
好的 C 代码通常使用以下几个选项之一来处理字符串:
使用固定缓冲区 和snprintf
,只要您不介意固定缓冲区。
使用有界字符串函数,例如strlcpy
和strlcat
。这些是 BSD 扩展。
使用跟踪字符串长度的自定义字符串点,并使用 和 编写您自己的memcpy
函数malloc
。
如果该代码是书中的逐字副本,则作者要么不了解 C,要么不是安全专家,要么两者兼而有之。
也可能是他使用了错误配置的编译器,明确禁止使用某些已知可能不安全的函数。当编译器无法区分安全、不安全和潜在不安全时,这是一个有问题的做法,并且一直在妨碍。
strn 系列的原因是为了防止您溢出缓冲区。如果您从调用者那里传递数据并且盲目地相信它正确地以空值终止并且不会溢出您将其复制到的缓冲区,那么您将被缓冲区溢出攻击所拥有。
效率差异可以忽略不计。strn 系列可能会稍微慢一些,因为它需要不断检查您是否没有溢出。
strncpy(dest, src, strlen(src)); 与 strcpy(dest, src) 相同;所以这里没有区别,但是..
strcpy 可能会导致安全漏洞,因为您不知道字符串有多长。聪明的人可以使用它覆盖您服务器上的某些内容。
对 strcpy 使用 strncpy 与它的执行速度几乎没有关系,但 strncpy 大大降低了缓冲区溢出攻击的可能性。在 C 中,指针是最强大的,但它们也使系统易受攻击。
从一本好的 Hack-Proofing 书中摘录可能会对您有所帮助。
许多溢出错误是错误的字符串操作的结果。诸如 strcpy() 之类的调用在复制字符串之前不会检查字符串的长度。结果是可能发生缓冲区溢出。预计会出现 NULL 终止符。从某种意义上说,攻击者依靠这个漏洞来利用机器;然而,这也意味着攻击者注入的缓冲区也必须不含 NULL 字符。如果攻击者插入一个 NULL 字符,字符串副本将在整个有效负载插入之前终止。