函数strcpy总是危险的吗?

时间:2011-03-15 20:12:34

标签: c security

strcpy,gets等功能是否总是危险的?如果我写这样的代码怎么办?

int main(void)
{

char *str1 = "abcdefghijklmnop";
char *str2 = malloc(100); 
strcpy(str2, str1);


}

这样函数不接受参数(参数...),并且str变量总是相同的长度...这里是16或稍微多一些,具体取决于编译器版本......但是100将会足以满足2011年3月的行动:)。 有没有办法让黑客利用上面的代码? 10倍!

9 个答案:

答案 0 :(得分:13)

绝对不是。与Microsoft marketing campaign的非标准功能相反,strcpy在正确使用时是安全的

以上是多余的,但大多数都是安全的。唯一可能的问题是您没有检查malloc返回值,因此您可能正在取消引用null(如kotlinski所指出的)。在实践中,这可能会立即导致SIGSEGV和程序终止。

使用不当和危险的是:

char array[100];
// ... Read line into uncheckedInput
// Extract substring without checking length
strcpy(array, uncheckedInput + 10);

这是不安全的,因为strcpy可能会溢出,导致未定义的行为。实际上,这很可能会覆盖其他局部变量(本身就是一个主要的安全漏洞)。其中一个可能是返回地址。通过return to lib C攻击,攻击者可以使用system之类的C函数来执行任意程序。溢出还有其他可能的后果。

但是,gets确实本质上不安全,并将从下一版本的C(C1X)中删除。根本没有办法确保输入不会溢出(导致上面给出的相同后果)。有些人认为与已知输入文件一起使用时是安全的,但实际上没有理由使用它。 POSIX的getline是一个更好的选择。

此外,str1的长度不会因编译器而异。它应该总是17,包括终止NUL。

答案 1 :(得分:5)

是的,这很危险。经过5年的维护,您的代码将如下所示: int main(void) {

char * str1 =“abcdefghijklmnop”;

{这里插入了足够多的行,以便str1和str2不会在屏幕上相互靠近}}

char * str2 = malloc(100); strcpy(str2,str1);

}

此时,有人会将str1更改为

str1 =“这是一个非常长的线索,现在将超过任何缓冲区用于复制,除非预先检查弦的限制。并且很少有人记得在这个问题上存在问题5岁的BUGGY计划“

并忘记查看str1的使用位置,然后随机错误将开始发生...

答案 2 :(得分:4)

你有力地把完全不同的东西塞进一个类别。

函数gets确实总是很危险。无论你愿意采取什么步骤以及你愿意采取多少防御措施,都无法安全地拨打gets

如果您愿意采取[简单]必要步骤以确保拨打strcpy安全,那么功能strcpy绝对安全。

这已经将getsstrcpy置于极为不同的类别中,这些类别在安全方面没有任何共同之处。

针对strcpy的安全方面的流行批评完全基于轶事社会观察而非正式事实,例如“程序员很懒惰,不称职,所以不要让他们使用strcpy”。在C编程的背景下,这当然是完全无稽之谈。遵循这个逻辑,我们也应该完全相同的原因声明除法运算符完全不安全。

实际上,strcpy无任何问题。另一方面,gets是一个完全不同的故事,正如我上面所说的那样。

答案 3 :(得分:1)

只要您知道目标缓冲区足够大以容纳源字符串的字符,

strcpy就没有危险;否则strcpy会愉快地复制比你的目标缓冲区所能容纳的更多字符,这可能会导致一些不幸的后果(堆栈/其他变量覆盖,这可能导致崩溃,堆栈粉碎攻击& co。)。

但是:如果您在输入中有一个尚未检查的通用char *,唯一可以确定的方法是将strlen应用于此类字符串并检查它是否对您来说太大了缓冲;但是,现在你必须遍历整个源字符串两次,一次用于检查其长度,一次用于执行复制。

这是次优的,因为如果strcpy稍微提高一点,它可以接收缓冲区大小的参数,如果源字符串太长则停止复制;在一个完美的世界中,这就是strncpy的表现(遵循其他strn***函数的模式)。但是,这是一个完美的世界,而strncpy并非旨在实现此目的。相反,非标准(但很受欢迎)的替代方案是strlcpy,它不会超出目标缓冲区的范围,而是截断。

有几个CRT实现不提供此功能(特别是glibc),但您仍然可以获得其中一个BSD实现并将其放入您的应用程序中。标准(但较慢)的替代方法可以是使用snprintf"%s"作为格式字符串。

那就是说,既然你是用C ++编程的( 编辑 我现在看到C ++标签已被删除了),你为什么不避免所有的C字符串废话(显然你可以)和std::string一起去?所有这些潜在的安全问题都消失了,字符串操作变得更加容易。

答案 4 :(得分:1)

malloc可能失败的唯一方法是发生内存不足错误,这本身就是一场灾难。您无法从中可靠地恢复,因为几乎任何东西都可能再次触发它,并且操作系统可能会终止您的进程。

答案 5 :(得分:0)

您的代码不安全。 malloc的返回值未选中,如果失败并返回0,strcpy将给出未定义的行为。

除此之外,我认为除了示例基本上没有做任何事情之外没有任何问题。

答案 6 :(得分:0)

正如您所指出的,在有限的情况下,strcpy并不危险。更典型的做法是接受一个字符串参数并将其复制到本地缓冲区,这就是当事情变得危险并导致缓冲区溢出时。只需记住在调用strcpy之前检查你的拷贝长度,然后在null之后终止字符串。

答案 7 :(得分:0)

除了潜在的解除引用NULL(因为你不检查来自malloc的结果)是UB并且可能不是安全威胁之外,没有潜在的安全问题。

答案 8 :(得分:0)

gets()始终不安全;其他功能可以安全使用 即使您完全控制输入,gets()也是不安全的 - 有一天,该程序可能由其他人运行。

使用gets()的唯一安全方法是将它用于单个运行的东西:创建源;编译;跑;删除二进制文件和源文件;解释结果。