几天前我参加了一次面试,收到了以下需求:
编写一个库函数来查找数组的MIN元素。使其尽可能安全。好吧,所以很明显,那里的口音是关于安全的。语言是C,公司是在嵌入式领域。后来我问面试官,他们是否至少能向我解释一下这里的情况,因为我真的很想学习,但他不太健谈。。。所以,我把谷歌搞得天翻地覆,但我没有找到具体的解决方案来满足这个请求。我是C的新手。这里可能出现哪些安全缺陷?危险信号是什么?我知道我们应该注意数组边界,因为溢出它会导致内存问题,而且我们可以很容易地从随机内存中写入/读取。但除此之外,我应该寻找什么?任何反馈都将非常有用!谢谢大家!
在C中搜索数组实际上只有两种方法。要么明确告诉你数组中有多少元素,要么你可以检查某种值来指示数组的末尾(比如字符串的' '
(。
例如,如果使用第一种情况,并且我们有一个int
s数组,那么这个:
int minInt(int array[],size_t num_elements){
if(array==NULL || num_elements==0)
return -1;
size_t i;
int min = array[0];
for(i = 1; i < num_elements; ++i)
if(array[i] < min)
min = array[i];
return min;
}
是一个很好的解决方案。例如,如果我们使用第二种情况,并且我们有一个C字符串形式的数组char
s,并且' '
表示数组的末尾,那么可能是这样的:
char minChar(char array[]){
if(array == NULL)
return -1;
size_t i;
char min = array[0];
for(i = 0; array[i] != ' '; ++i)
if(array[i] < min)
min = array[i];
return min;
}
这将是一个很好的回应。这在很大程度上取决于系统的具体情况,只有当您能够确定停止值没有丢失时,第二种情况才是安全的。
需要考虑两个方面:
- 内存管理
- 并发
内存管理
正如您所提到的,您使用的是C,这是一种低级语言,函数很容易出错并访问错误的内存位置,特别是当有许多指针传递时。因此,最好确保您正在访问的数组的边界是什么,并强制执行一些规则以避免传递这些规则。
当攻击者更改参数,使函数可以从阵列外的内存位置返回数据时,可能会发生一些安全攻击!使用不同的更改参数多次重复该过程,内存中的数据就会泄露!
并发
这只适用于当你知道有多个线程在同一个程序上运行时,那么你可能想要一个关键部分来锁定你的函数正在使用的数组。
我相信你在网上找到的大多数功能都能安全地完成任务,也许你的面试官只是想让你和他讨论可能发生的威胁和攻击,以及你是如何意识到的。
安全性是我们需要在代码中涵盖的最有价值的功能,为了丰富这一级别,大多数时候我们需要选择像Java这样的安全环境,但在某些情况下(尤其是在嵌入式领域(,我们需要手动处理安全方式。在低级编程(c编程(中,存在两个最常见的安全问题:缓冲区溢出,双自由攻击。缓冲区溢出是指用户试图输入超出支持范围的数据量(短暂(,因此为了避免这种恶意安全,您需要尽可能多地覆盖边缘情况,并尽可能防止最"奇怪"的情况:(。
char the_array[100];
根据前面的声明,数组可以正常工作,直到用户/函数决定输入超过100个字符,如果你避免了程序崩溃,那你就很幸运了。因此,尽可能多地处理边缘案例,并创造性地阅读现实生活场景,你可以避免这些问题,有很多技巧可以帮助你。双重释放攻击:当您使用新的内存地址重新初始化指针时,意外释放指针两次就是这种情况。
char *ptr;
ptr = malloc(10 * sizeof(*ptr));
/* Doing stuff */
free(ptr);
这是指针的动态分配示例,为了避免双重免费攻击,您需要将ptr设置为null。
free(ptr);
ptr = NULL;
假设您对C语言编程有很好的了解,那么您需要尽可能避免每次使用后都会释放两次指针并使其无效。还有一个很好的工具可以帮助调试C中的内存,试着在程序的每次运行或测试中使用Valgrind
它可以帮助跟踪内存泄漏、双空闲、未初始化的变量。。。