C/C++ 數(shù)字操作

2021-05-28 10:19 更新

7.1 【必須】防止整數(shù)溢出

在計(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)存破壞

7.2 【必須】防止Off-By-One

在進(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)存破壞

7.3 【必須】避免大小端錯(cuò)誤

在一些涉及大小端數(shù)據(jù)處理的場(chǎng)景,需要進(jìn)行大小端判斷,例如從大段設(shè)備取出的值,要以大段進(jìn)行處理,避免端序錯(cuò)誤使用。

關(guān)聯(lián)漏洞:

  • 中風(fēng)險(xiǎn)-邏輯漏洞

7.4 【必須】檢查除以零異常

在進(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ù)

7.5 【必須】防止數(shù)字類型的錯(cuò)誤強(qiáng)轉(zhuǎn)

在有符號(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)-邏輯漏洞

7.6 【必須】比較數(shù)據(jù)大小時(shí)加上最小/最大值的校驗(yà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)存破壞
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)