每个C程序员必须注意哪些安全风险/漏洞?[关闭]


13

与硬件的密切联系存在许多安全风险,这与使用高级编程语言经过测试和验证的API形成对比。与诸如Java之类的语言相比,用C引起缓冲区溢出要容易得多。

每个C程序员都应该意识到哪些风险或漏洞(例如缓冲区溢出)(与C程序员相关的IE漏洞)?这些可能导致什么问题?如何避免它们,以及导致这些错误在程序中发生的常见错误是什么?


这个列表呢:owasp.org/index.php/Category : OWASP_Top_Ten_Project 还需要什么呢?
S.Lott

2
@ S.Lott:这似乎与Web开发中的安全性问题息息相关。总体而言,似乎比我实际要求的资源更多。
安托

@Anto:请更新问题,以区分所有有关安全性的资源和您要询问的安全性。
S.Lott

@ S.Lott:我不确定你的意思。我要求对大多数C程序员都重要的安全性,即诸如缓冲区溢出之类的事情以及在C中可能发生的其他事情
。– Anto

@Anto:“一般来说,[网络安全?]上的资源似乎比我实际需要的更多”。似乎是在说您要问的不是Web安全的某种安全。真正?如果是这样,请更新问题以解释您要查找的内容。假?然后,您询问Web安全,在这种情况下,为什么您的问题中没有提到OWASP列表?
S.Lott

Answers:


13

缓冲区溢出是一大麻烦。默认情况下,C中的任何内容都不会进行范围检查,因此覆盖缓冲区非常容易。有一个标准的库函数,gets()它不能因缓冲区溢出而停止,并且几乎不应该使用。

有一些实现级别的技术会阻碍开发,例如加扰堆块,但不会阻止本地缓冲区中的缓冲区溢出,这经常会做一些有趣的事情,例如更改函数将返回的地址。

C语言中没有好的通用解决方案。许多库函数的版本都会限制它们的写入量。尽管计算可能很笨拙。只要运行适当的测试,就有一种软件可以在测试中检测堆缓冲区溢出,并且堆栈溢出通常会在测试中崩溃。除此之外,还需要进行仔细的编码和代码审查。

一个相关的问题是写到一个只有一个字符太小的缓冲区的问题,由于'\0'终止符,忘记了n个字符长的C字符串在内存中需要n + 1个字符。如果攻击者可以设法在没有终止符的情况下存储字符串,则任何期望字符串的C函数都将继续处理,直到命中零字节为止,这可能会导致复制或输出超出所需信息的信息(或击打受保护的内存以进行DOS攻击) )。同样,解决方案是意识,关怀和代码审查。

printf()家庭还有另一个风险。如果您曾经写过char * str; ... printf(str);,那么str在打印时如果包含'%' ,就表示自己正在准备解决问题。该%n格式指令允许printf()写入到内存中。解决方案是printf("%s", str);puts(str);。(此外,请使用C99 snprintf()代替sprintf()。)

使用无符号整数,尤其是作为循环索引,可能会导致问题。如果将一个小的负值分配给一个无符号的,则将得到一个很大的正值。这可能会破坏诸如仅处理某事物的N个实例之类的东西,或者破坏诸如之类的有限功能strncpy()。检查所有无符号整数。您可能要避免unsigned short,因为其中一个较大的值将转换为较大的正值int

别忘了C中的字符常量实际上是个int。编写类似之类的内容char c; while((c = getchar()) != EOF) ...很容易失败,因为它EOF无法用表示char

我可以想到很多特征性的C错误,但是这些错误可能会导致安全问题。


printf("%s", str)puts(str)执行相同的工作时,无需使用裸线。
Blrfl 2011年

@Blrfl,但不puts附加换行符printf
2011年

也可以做fputs(str, stdout),而事实并非如此。
Blrfl 2011年

关于整数溢出:使用带符号的int是没有解决方案的,因为溢出它们会导致UB。唯一(痛苦的)解决方案是正式证明您永远不会溢出,或者在运行时进行检查(但请正确检查,这在不溢出检查的情况下也很棘手)。
sleske '16

@DavidThornley:C11和C ++ 14标准由于其危险性而从标准库中删除了gets()函数。
毁灭者

5

一些C特有的风险包括:缓冲区溢出格式化字符串攻击整数溢出


1
缓冲区溢出没有C特有的-任何带有指针的语言都可以拥有。整数溢出适用于几乎所有语言,并且也很容易在托管代码中发生。
史蒂夫

1
@Steve,它不是真正导致问题的指针,而是该语言如何不强制执行数组界限。
Doug T.

2
@Steve的问题不是在问仅涉及C的东西,而是C程序员应该注意的东西。
AttackingHobo

1
@Steve:C非常容易受到缓冲区溢出的影响,部分原因是缺乏对范围检查的支持,以及会为您高兴地溢出缓冲区的库函数的数量。
David Thornley,

我理解这个问题尤其是关于C的问题,但是我认为值得澄清的是,如果从上下文中读出答案,则这些风险更为普遍。特别是托管代码的开发人员(IMHO)对安全性过于自满,并且整数溢出尤其会影响大多数语言。
史蒂夫

4

这是一个容易遗漏的风险,可能会导致需要花费数小时才能解决的问题。

考虑以下代码,该代码将毫无问题地进行编译。

if(lpstr_current_state = CONST_EMERGENCY_STATE_HOLY_CRAP)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}

当您检查是否lpstr_current_state存在时,CONST_EMERGENCY_STATE_HOLY_CRAP您实际上是在分配。最好始终将常量变量放在左侧。当您将常量放在左侧时,编译器将失败,因为您无法为变量分配值。

if(CONST_EMERGENCY_STATE_HOLY_CRAP = lpstr_current_state)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}

然后,您可以轻松地对自己说:“天哪,这可能很糟糕”,同时将代码固定为...

if(CONST_EMERGENCY_STATE_HOLY_CRAP == lpstr_current_state)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}

7
与其他一些问题不同,这对于编译器来说很容易捕获并标记为警告。不幸的是,并非所有的编译器都使它易于实现。
David Thornley

2
这可能会发生在C语言以外的任何语言以及使用=和的任何语言中==
FrustratedWithFormsDesigner

3
这也不是真正的安全漏洞,这是一个错误。
克里斯·皮特曼

1
这些称为尤达条件。

2
@Kristofer Hoch:如果我们要把任何可能的C bug称为风险,并在这里加以考虑,我们将需要一个更大的论坛。
David Thornley

0

仅存在一个安全风险:外面有人会竭尽所能捕获软件中的任何漏洞并为自己谋取利益而利用这一事实。其他一切都从那里开始。

因此,当您认为“没有人在他们的正确头脑中会……”时,您需要立即思考“除了想要入侵他人计算机的人会做到这一点”。

最大的后果是,无论何时您对外部事件做出反应(例如,通过处理从外部传递来的数据),都必须假定此数据受到了您最大的敌人的控制。


虽然我同意第二和第三段,但在我看来,将所有责任归咎于攻击者。成功进行攻击总是需要两个条件:一个搞砸了程序员的程序员和一个抓住了程序员的攻击者。然而,安全漏洞是存在之前,攻击者可以利用它。因此,应该责怪程序员。
cmaster-恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.