71

我正在寻找为什么 strncpy 被认为是不安全的。是否有人对此有任何类型的文档或使用它的利用示例?

4

5 回答 5

46

看看这个网站;这是一个相当详细的解释。基本上,strncpy()不需要 NUL 终止,因此容易受到各种攻击。

于 2009-05-15T17:20:06.660 回答
12

最初的问题显然是strcpy(3)不是内存安全操作,因此攻击者可以提供比缓冲区更长的字符串,这会覆盖堆栈上的代码,如果精心安排,可以执行攻击者的任意代码。

但是strncpy(3)的另一个问题是它不会在目的地的每种情况下都提供空终止。(想象一个源字符串比目标缓冲区长。)未来的操作可能期望在相同大小的缓冲区之间符合 C 以 nul 结尾的字符串,并且当结果被复制到第三个缓冲区时下游会发生故障。

使用 strncpy(3) 比 strcpy(3) 更好,但像 strlcpy(3) 这样的东西更好。

于 2012-06-01T07:12:07.457 回答
7

为了安全地使用 strncpy,必须 (1) 手动将空字符粘贴到结果缓冲区,(2) 事先知道缓冲区以空结尾,并将 (length-1) 传递给 strncpy,或者 (3) 知道永远不会使用任何不会将其长度绑定到缓冲区长度的方法来复制缓冲区。

重要的是要注意 strncpy 会将缓冲区中复制的字符串之后的所有内容填零,而其他长度受限的 strcpy 变体不会。这在某些情况下可能会消耗性能,但在其他情况下会带来安全优势。例如,如果使用 strlcpy 将“supercalifragilisticexpalidocious”复制到缓冲区,然后复制“it”,则缓冲区将保存“it^ercalifragilisticexpalidocious^”(使用“^”表示零字节)。如果缓冲区被复制为固定大小的格式,额外的数据可能会随之标记。

于 2010-10-22T17:29:22.117 回答
5

该问题基于“加载”的前提,这使得问题本身无效。

这里的底线strncpy是不被认为是不安全的,也从未被认为是不安全的。可以附加到该函数的唯一“不安全”声明是 C 内存模型和 C 语言本身的普遍不安全的广泛声明。(但这显然是一个完全不同的话题)。

在 C 语言领域内,对某种固有的“不安全性”的误导性信念strncpy源自于广泛使用strncpy的“安全字符串复制”的可疑模式,即此功能不做且从未打算用于的事情。这种用法确实很容易出错。但即使你在“高度容易出错”和“不安全”之间加上一个等号,它仍然是一个使用问题(即缺乏教育问题)而不是strncpy问题。

基本上,可以说唯一的问题strncpy是一个不幸的命名,这使得新手程序员假设他们理解这个函数的作用,而不是实际阅读规范。查看函数名称,一个不称职的程序员会认为它strncpy是 的“安全版本” strcpy,而实际上这两个函数完全不相关。

例如,可以针对除法运算符提出完全相同的主张。正如你们大多数人所知,关于 C 语言的最常见问题之一是“我认为它1/2会计算结果,0.5但我得到了0。为什么?” 然而,我们不会仅仅因为语言初学者倾向于误解它的行为就声称除法运算符是不安全的。

再举一个例子,我们之所以称伪随机数生成器函数为“不安全”,只是因为不称职的程序员常常对他们的输出并非真正随机这一事实感到不快。

这正是它的strncpy功能。就像初学者程序员需要时间来了解伪随机数生成器的实际作用一样,他们也需要时间来了解strncpy实际作用。学习这strncpy是一个转换函数需要时间,用于将零结尾的字符串转换为固定宽度的字符串。学习strncpy与“安全字符串复制”完全无关并且不能有意义地用于该目的需要时间。

strncpy诚然,语言学生学习目的通常比使用除法运算符解决问题要花更长的时间。但是,这是针对strncpy.

PS 在接受的答案中链接的 CERT 文档专门用于:展示典型的无能滥用strncpy功能作为“安全”版本的不安全性strcpy。它绝不是要声称strncpy自己在某种程度上是不安全的。

于 2014-09-10T14:50:35.120 回答
2

Git 2.19(Q3 2018)的一个pathc发现太容易误用系统API函数如strcat()strncpy(); ...并禁止此代码库中的这些功能。

请参阅Jeff King ( ) 的提交 e488b7a提交 cc8fdae提交 1b11b64(2018 年 7 月 24 日)和提交 c8af66a(2018 年 7 月 26 日(由Junio C Hamano 合并 -- --提交 e28daf2中,2018 年 8 月 15 日)peff
gitster

banned.h: 标记strcat()为禁止

strcat()函数具有与strcpy().
作为奖励,很容易意外地以二次方告终,因为每个后续调用都必须遍历现有字符串。

最后一次strcat()调用在f063d38中消失(守护进程:重生时使用 cld->env_array,2015-09-24,Git 2.7.0)。
通常,strcat()可以用动态字符串(strbufxstrfmt)替换,或者xsnprintf如果您知道长度是有界的,则可以替换为。

于 2018-08-19T17:05:03.927 回答