在計(jì)算時(shí)需要考慮整數(shù)溢出的可能,尤其在進(jìn)行內(nèi)存操作時(shí),需要對(duì)分配、拷貝等大小進(jìn)行合法校驗(yàn),防止整數(shù)溢出導(dǎo)致的漏洞。
錯(cuò)誤(該例子在計(jì)算時(shí)產(chǎn)生整數(shù)溢出)
const kMicLen = 4;
// 整數(shù)溢出
void Foo() {
int len = 1;
char payload[10] = { 0 };
char dst[10] = { 0 };
// Bad, 由于len小于4字節(jié),導(dǎo)致計(jì)算拷貝長(zhǎng)度時(shí),整數(shù)溢出
// len - MIC_LEN == 0xfffffffd
memcpy(dst, payload, len - kMicLen);
}
正確例子
void Foo() {
int len = 1;
char payload[10] = { 0 };
char dst[10] = { 0 };
int size = len - kMicLen;
// 拷貝前對(duì)長(zhǎng)度進(jìn)行判斷
if (size > 0 && size < 10) {
memcpy(dst, payload, size);
printf("memcpy good\n");
}
}
關(guān)聯(lián)漏洞:
高風(fēng)險(xiǎn)-內(nèi)存破壞
在進(jìn)行計(jì)算或者操作時(shí),如果使用的最大值或最小值不正確,使得該值比正確值多1或少1,可能導(dǎo)致安全風(fēng)險(xiǎn)。
錯(cuò)誤:
char firstname[20];
char lastname[20];
char fullname[40];
fullname[0] = '\0';
strncat(fullname, firstname, 20);
// 第二次調(diào)用strncat()可能會(huì)追加另外20個(gè)字符。如果這20個(gè)字符沒有終止空字符,則存在安全問(wèn)題
strncat(fullname, lastname, 20);
正確:
char firstname[20];
char lastname[20];
char fullname[40];
fullname[0] = '\0';
// 當(dāng)使用像strncat()函數(shù)時(shí),必須在緩沖區(qū)的末尾為終止空字符留下一個(gè)空字節(jié),避免off-by-one
strncat(fullname, firstname, sizeof(fullname) - strlen(fullname) - 1);
strncat(fullname, lastname, sizeof(fullname) - strlen(fullname) - 1);
對(duì)于 C++ 代碼,再次強(qiáng)烈建議使用 string
、vector
等組件代替原始指針和數(shù)組操作。
關(guān)聯(lián)漏洞:
高風(fēng)險(xiǎn)-內(nèi)存破壞
在一些涉及大小端數(shù)據(jù)處理的場(chǎng)景,需要進(jìn)行大小端判斷,例如從大段設(shè)備取出的值,要以大段進(jìn)行處理,避免端序錯(cuò)誤使用。
關(guān)聯(lián)漏洞:
中風(fēng)險(xiǎn)-邏輯漏洞
在進(jìn)行除法運(yùn)算時(shí),需要判斷被除數(shù)是否為零,以防導(dǎo)致程序不符合預(yù)期或者崩潰。
錯(cuò)誤:
double divide(double x, double y) {
return x / y;
}
int divide(int x, int y) {
return x / y;
}
正確:
double divide(double x, double y) {
if (y == 0) {
throw DivideByZero;
}
return x / y;
}
關(guān)聯(lián)漏洞:
低風(fēng)險(xiǎn)-拒絕服務(wù)
在有符號(hào)和無(wú)符號(hào)數(shù)字參與的運(yùn)算中,需要注意類型強(qiáng)轉(zhuǎn)可能導(dǎo)致的邏輯錯(cuò)誤,建議指定參與計(jì)算時(shí)數(shù)字的類型或者統(tǒng)一類型參與計(jì)算。
錯(cuò)誤例子
int Foo() {
int len = 1;
unsigned int size = 9;
// 1 < 9 - 10 ? 由于運(yùn)算中無(wú)符號(hào)和有符號(hào)混用,導(dǎo)致計(jì)算結(jié)果以無(wú)符號(hào)計(jì)算
if (len < size - 10) {
printf("Bad\n");
} else {
printf("Good\n");
}
}
正確例子
void Foo() {
// 統(tǒng)一兩者計(jì)算類型為有符號(hào)
int len = 1;
int size = 9;
if (len < size - 10) {
printf("Bad\n");
} else {
printf("Good\n");
}
}
關(guān)聯(lián)漏洞:
高風(fēng)險(xiǎn)-內(nèi)存破壞
中風(fēng)險(xiǎn)-邏輯漏洞
在進(jìn)行數(shù)據(jù)大小比較時(shí),要合理地校驗(yàn)數(shù)據(jù)的區(qū)間范圍,建議根據(jù)數(shù)字類型,對(duì)其進(jìn)行最大和最小值的判斷,以防止非預(yù)期錯(cuò)誤。
錯(cuò)誤:
void Foo(int index) {
int a[30] = {0};
// 此處index是int型,只考慮了index小于數(shù)組大小,但是并未判斷是否大于0
if (index < 30) {
// 如果index為負(fù)數(shù),則越界
a[index] = 1;
}
}
正確:
void Foo(int index) {
int a[30] = {0};
// 判斷index的最大最小值
if (index >=0 && index < 30) {
a[index] = 1;
}
}
關(guān)聯(lián)漏洞:
高風(fēng)險(xiǎn)-內(nèi)存破壞
更多建議: