1.字符串操作安全
1.1 确保所有字符串都是以NULL结束
C语言中以 '\0'
作为字符串的结束符,即NULL结束符。
没有正确使用NULL结束符会导致缓冲区溢出和其他未定义的行为。
为了避免缓冲区溢出,常常会用相对安全的限制字符数量的字符串操作函数代替一些危险函数
- strncpy()
代替 strcpy()
- strncat()
代替 strcat()
- snprintf()
代替 sprintf()
- fgets()
代替 gets()
这些函数会截断超出指定限制的字符串,但是要注意他们并不能保证目标字符串总是以NULL结尾。
//错误释放,a后面没有NULL结束符
char a[16];
strncpy(a,"0123456789abcdef",sizeof(a));
上面的代码调用strncpy()后,a的字符串中是没有NULL结束符的。
//正确写法:截断字符串,保证字符串以NULL结束
char a[16];
strncpy(a,"0123456789abcdef",sizeof(a)-1);
a[sizeof(a)-1] = '\0';
1.2 不要将不明确的字符串写到固定长度的数组中
边界不明确的字符串(例如来自 gets(), getenv(), scanf()的字符串)长度可能大于目标数组长度,直接拷贝到固定长度的数组中容易导致缓冲区溢出。
//错误示例:
char buff[256];
char *editor = getenv("EDITOR");
if(editor != NULL)
{
strcpy(buff,editor);
}
editor实际长度可能大于256导致溢出。
//正确写法:计算字符串的实际长度,使用malloc分配指定长度的内存
char *buff;
char *editor = getenv("EDITOR");
if(editor != NULL)
{
buff = malloc(strlen(editor)+1);
if(buff != NULL)
{
strcpy(buff,editor);
}
}
2.整数安全
C99标准定义了整型提升、整型转换级别以及普通算数转换的整型操作。不过这些操作实际上也带来了安全风险。
2.1 避免整数溢出
当一个证书被增加超过起最大值时会发生整数上溢,被减小小于其最小值时会发生下溢。带符号和无符号的数都可能发生溢出。
//有符号和无符号整数的上溢和下溢
int i;
unsigned int j;
i = INT_MAX; //2147483647
i++;
printf("i = %d\n",i); i = -214748348
j = UINT_MAX; //4294967295
j++;
printf("j = %u\n", j); //0
i = INT_MIN; //-2147483648
i--;
printf("i = %d\n",i); //i = 2147483647
j = 0;
j--;
printf("j = %u\n", j); //4294967295
在长度加减时,加上长度检查
//length 可能小于 FSM_HDRLEN
unsigned int length;
length -= FSM_HDRLEN;