问题描述
|
strcpy,gets等函数是否总是很危险?如果我编写这样的代码怎么办:
int main(void)
{
char *str1 = \"abcdefghijklmnop\";
char *str2 = malloc(100);
strcpy(str2,str1);
}
这样,该函数不接受参数(参数...),并且str变量将始终具有相同的长度...根据编译器版本的不同,此处长度为16或稍长一些...但是yeah 100就足够了2011年3月:)。
黑客有没有办法利用上面的代码?
10倍!
解决方法
绝对不。与Microsoft的非标准功能营销活动相反,正确使用properly1是安全的。
以上是多余的,但大多数情况下都是安全的。唯一的潜在问题是您没有检查
malloc
返回值,因此您可能会取消引用null(如kotlinski所指出)。实际上,这可能会立即导致SIGSEGV和程序终止。
不当和危险的使用将是:
char array[100];
// ... Read line into uncheckedInput
// Extract substring without checking length
strcpy(array,uncheckedInput + 10);
这是不安全的,因为strcpy可能会溢出,从而导致未定义的行为。实际上,这很可能会覆盖其他局部变量(本身就是一个重大的安全漏洞)。其中之一可能是寄信人地址。通过返回lib C攻击,攻击者可以使用诸如system
之类的C函数来执行任意程序。溢出还有其他可能的后果。
但是,ѭ5确实本质上是不安全的,它将从下一版本的C(C1X)中删除。根本没有办法确保输入不会溢出(导致上面给出的相同结果)。有人认为与已知的输入文件一起使用时它是安全的,但实际上没有理由使用它。 POSIX的getline
是更好的选择。
另外,str1
的长度不会因编译器而异。它应始终为17,包括终止的NUL。
,是的,这很危险。经过5年的维护,您的代码将如下所示:
int main(void)
{
char *str1 = \"abcdefghijklmnop\";
{enough lines have been inserted here so as to not have str1 and str2 nice and close to each other on the screen}
char *str2 = malloc(100);
strcpy(str2,str1);
}
到那时,有人会去并将str1更改为
str1 = \“这是一个非常长的字符串,现在它将超载任何用于复制它的缓冲区,除非采取了预防措施以检查该字符串的限制。并且有很少的人记得在五年内解决这个问题旧的BUGY程序\“
忘了看在哪里使用str1,然后随机错误将开始发生...
,您正在将完全不同的内容塞入一类。
ѭ5的功能确实总是很危险的。无论您愿意采取什么步骤以及愿意采取何种防御措施,都无法对ѭ5进行安全呼叫。
如果您愿意采取[简单]必要的步骤来确保对strcpy
的调用是安全的,则函数strcpy
是绝对安全的。
那已经将ѭ5和ѭ1划分为截然不同的类别,它们在安全性方面没有共同之处。
针对“ 1”安全方面的流行批评完全基于轶事社会观察,而不是正式事实,例如\“程序员懒惰且无能,所以不要让他们使用strcpy
\”。当然,在C编程的上下文中,这完全是胡说八道。遵循此逻辑,出于完全相同的原因,我们还应将除法运算符声明为完全不安全。
实际上,ѭ1毫无问题。另一方面,正如我上面所说,“ 5”是一个完全不同的故事。
,只要知道目标缓冲区足够大以容纳源字符串的字符,1并不危险。否则,“ 1”将快乐地复制超过目标缓冲区可容纳的字符数,这可能会导致若干不幸的后果(堆栈/其他变量被覆盖,这可能导致崩溃,堆栈粉碎攻击等)。
但是:如果输入中没有检查通用的char *
,确保唯一的方法就是将strlen
应用于这样的字符串,并检查它是否对于缓冲区太大。但是,现在您必须遍历整个源字符串两次,一次用于检查其长度,一次用于执行复制。
这不是次优的,因为如果ѭ1稍微先进一点,它可以接收缓冲区的大小作为参数,并且如果源字符串太长则停止复制;在一个理想的世界中,这就是strncpy
的执行方式(遵循其他strn***
功能的模式)。但是,这不是一个完美的世界,strncpy
并非旨在做到这一点。取而代之的是,非标准(但很流行)的替代方法是strlcpy
,它会截断而不是超出目标缓冲区的边界。
几个CRT实现不提供此功能(特别是glibc),但是您仍然可以获取一种BSD实现并将其放入您的应用程序中。一个标准的(但较慢的)替代方法可以是使用snprintf
和\"%s\"
作为格式字符串。
就是说,既然您正在使用C ++进行编程(编辑,我现在看到C ++标记已被删除),为什么不避免所有的C字符串废话(显然,可以的话)并选择with30ѭ ?所有这些潜在的安全问题都消失了,字符串操作变得更加容易。
,malloc可能失败的唯一方法是发生内存不足错误,这本身就是一场灾难。您无法可靠地从中恢复,因为几乎任何事情都可能再次触发它,并且操作系统可能仍然会终止您的进程。
,您的代码不安全。 malloc
的返回值未经检查,如果失败并返回0,strcpy
将给出未定义的行为。
除此之外,除了示例基本不执行任何操作外,我没有发现其他问题。
,正如您所指出的,在受限制的情况下,strcpy并不危险。通常,采用字符串参数并将其复制到本地缓冲区中,在这种情况下,情况可能会变得很危险并导致缓冲区溢出。只需记住在调用strcpy之前检查您的副本长度,然后将null终止字符串即可。
,除了可能会取消引用UB(可能不会带来安全威胁)而取消引用NULL(因为您不检查malloc的结果)之外,也没有潜在的安全问题。
,gets()
总是不安全的;其他功能可以安全使用。
即使完全控制了输入,33ѭ也不安全-某天,该程序可能会由其他人运行。
使用gets()
的唯一安全方法是将其用于单个运行项:创建源;编译跑;删除二进制文件和源代码;解释结果。