与硬件的密切联系存在许多安全风险,这与使用高级编程语言经过测试和验证的API形成对比。与诸如Java之类的语言相比,用C引起缓冲区溢出要容易得多。
每个C程序员都应该意识到哪些风险或漏洞(例如缓冲区溢出)(与C程序员相关的IE漏洞)?这些可能导致什么问题?如何避免它们,以及导致这些错误在程序中发生的常见错误是什么?
与硬件的密切联系存在许多安全风险,这与使用高级编程语言经过测试和验证的API形成对比。与诸如Java之类的语言相比,用C引起缓冲区溢出要容易得多。
每个C程序员都应该意识到哪些风险或漏洞(例如缓冲区溢出)(与C程序员相关的IE漏洞)?这些可能导致什么问题?如何避免它们,以及导致这些错误在程序中发生的常见错误是什么?
Answers:
缓冲区溢出是一大麻烦。默认情况下,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)
执行相同的工作时,无需使用裸线。
puts
附加换行符printf
。
fputs(str, stdout)
,而事实并非如此。
这是一个容易遗漏的风险,可能会导致需要花费数小时才能解决的问题。
考虑以下代码,该代码将毫无问题地进行编译。
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();
}
=
和的任何语言中==
。
仅存在一个安全风险:外面有人会竭尽所能捕获软件中的任何漏洞并为自己谋取利益而利用这一事实。其他一切都从那里开始。
因此,当您认为“没有人在他们的正确头脑中会……”时,您需要立即思考“除了想要入侵他人计算机的人会做到这一点”。
最大的后果是,无论何时您对外部事件做出反应(例如,通过处理从外部传递来的数据),都必须假定此数据受到了您最大的敌人的控制。