安全的C语言和大学-针对缓冲区溢出进行培训

3
我最近完成了一门C语言的大学课程,因此我缺乏经验。
一些大学倾向于教授他们的学生安全编程,或者至少一些元素。这里甚至有一个视频(来自这里)。
在C语言中,复制字符串需要使用strcpy或string.h函数。如何在日常编程中安全地使用它?您是否有一些处理分配以防止缓冲区溢出的函数?CERT安全编码标准为C提供了示例和合规解决方案:
int main(int argc, char *argv[]) {
  /* ... */
  char prog_name[128];
  strcpy(prog_name, argv[0]);
  /* ... */
}

他们的替代方案是:

int main(int argc, char *argv[]) {
  /* ... */
  char *prog_name = (char *)malloc(strlen(argv[0])+1);
  if (prog_name != NULL) {
    strcpy(prog_name, argv[0]);
  }
  else {
    /* Couldn't get the memory - recover */
  }
  /* ... */
}

这里摘自第二个示例

但据我了解,这只是更具挑战性、需要更多代码和更多工作。为什么没有人改变库本身呢?或者至少为什么没有人提供一个安全的替代库或函数,以正确处理这个问题呢?

谢谢阅读, wishi


嗨,哈佛大学还有其他关于编程的视频吗? - yesraaj
7个回答

9
这个问题的 Posix 函数(几乎所有系统都有)是 strdup()。如果您不想分配新内存并已经有一个要使用的缓冲区,则可以使用 strcpy(),但是您最好知道该缓冲区的大小以及字符串是否适合其中。如果您不知道字符串是否适合,则有 strncpy() 可以只复制给定数量的字符。因此,您可以将复制的数量限制为缓冲区的大小。
除此之外,还有许多处理不同字符串大小的字符串库。
另外,由于您标记它为 C++:有 std::string 可以为您完成所有内存管理,而不会给您带来这些问题。

2

OpenBSDl(strlcpy,strlcat)函数通常比n函数更好,它们既快速又易于安全使用,但它们是非标准的。然而,它们是BSD许可证,因此您可以在任何程序中包含已知的良好实现,从而使您既可以跨平台又可以保持安全。

对于Windows,如果您不关心可移植性,可以使用*_s函数。


n函数更好在哪里? - oz10
如此描述:http://www.gratisoft.us/todd/papers/strlcpy.html要有效地使用“n函数”,仍有许多工作要做。 - benno

2
使用 strncpy 函数:
#define BUFSIZE 127
int main(int argc, char *argv[]) {
  /* ... */
  char prog_name[BUFSIZE + 1];
  strncpy(prog_name, argv[0], BUFSIZE);
  progname[BUFSIZE]= '\0';
  /* ... */
}

大多数 str* 函数有 *n* 个版本。


最好使用BUFSIZE作为长度并分配BUFSIZE + 1 ;-). - Toon Krijthe

1

如果我理解正确,你的真正问题是为什么API功能不更安全。

一个原因是C库是遗留问题(现在改变已经太晚了)。

然而,主要原因是库被设计成最小化,只能执行最基本的操作,用户有责任确保调用正确。如果它做了任何过度检查,那么每次调用时都会付出一定代价,即使用户可以保证由于其他原因不会出现问题。这在许多API中非常常见。

话虽如此,存在足够的提供更安全替代方案的库,它们只是不包含在标准库中。此外,许多从事高级工作的人使用C++,它有许多标准类库来处理这些问题。


0

实际上,微软提供了替代 CRT 函数的安全选项。但我认识的每个人都讨厌它们,并禁用了警告,称您不应使用旧函数。如果您想要安全性,也许您应该使用 C++。然后使用 STL 字符串或类似 Qt 的东西。

好吧,或者您可以转向像 .NET 或 Java 这样的平台,这些平台通常不会受到这些问题的困扰(您的应用程序可能会崩溃,但无法通过缓冲区溢出注入代码到您的应用中)。

编辑: 启用数据执行保护 / NX(Vista 和 .NET 的默认设置),这对于传统平台也不应再是一个问题。


使用C++并不能神奇地阻止所有缓冲区溢出及其引发的问题。 - Thomas Owens
即使有strdup可用,当人们继续使用具有固定长度的malloc/strcpy时,也无法阻止缓冲区溢出。C++提供了替代方案,但并不强制执行。代码审查 - 无论如何都需要 - 可以强制使用这些替代方案。 - MSalters
@Thomas:我的意思是MSalters所写的。C++提供了许多安全替代普通CRT函数的方法,仅这一点就足以成为切换的理由了。 - OregonGhost
@Longpoke:我的意思是DEP/NX保护您免受通过缓冲区溢出进行的代码注入攻击,就像托管平台一样。我并没有说DEP/NX可以防止所有缓冲区溢出。 - OregonGhost
DEP/NX最多只是一种缓解措施。它们以前已经被绕过,即使你无法绕过它们,还有其他事情可以做,比如在堆栈上设置对任意函数的调用。 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

0

0
int main
(
    int argc, 
    char *argV[]
) 
{
   char prog_name[128];
   if (strlen(argV[0]) < sizeof(prog_name))
   {
       strcpy(prog_name, argV[0]);
   }
   else
   {
       printf("%s is too large for the internal buffer\n", argV[0]);
   }

   return 0;
}

个人讨厌的事情:放弃括号,sizeof是一个运算符而不是函数。括号用于类型,并且是sizeof参数的一部分,其外观类似于“转换”。 - unwind
感谢您的周到评论。 - EvilTeach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接