C/C++ 数字操作

2021-05-28 10:19 更新

7.1 【必须】防止整数溢出

在计算时需要考虑整数溢出的可能,尤其在进行内存操作时,需要对分配、拷贝等大小进行合法校验,防止整数溢出导致的漏洞。

错误(该例子在计算时产生整数溢出)

const kMicLen = 4;
// 整数溢出
void Foo() {
  int len = 1;
  char payload[10] = { 0 };
  char dst[10] = { 0 };
  // Bad, 由于len小于4字节,导致计算拷贝长度时,整数溢出
  // 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;
  // 拷贝前对长度进行判断
  if (size > 0 && size < 10) {
    memcpy(dst, payload, size);
    printf("memcpy good\n");
  }
}

关联漏洞:

  • 高风险-内存破坏

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

在进行计算或者操作时,如果使用的最大值或最小值不正确,使得该值比正确值多1或少1,可能导致安全风险。

错误:

char firstname[20];
char lastname[20];
char fullname[40];


fullname[0] = '\0';


strncat(fullname, firstname, 20);
// 第二次调用strncat()可能会追加另外20个字符。如果这20个字符没有终止空字符,则存在安全问题
strncat(fullname, lastname, 20);

正确:

char firstname[20];
char lastname[20];
char fullname[40];


fullname[0] = '\0';


// 当使用像strncat()函数时,必须在缓冲区的末尾为终止空字符留下一个空字节,避免off-by-one
strncat(fullname, firstname, sizeof(fullname) - strlen(fullname) - 1);
strncat(fullname, lastname, sizeof(fullname) - strlen(fullname) - 1);

对于 C++ 代码,再次强烈建议使用 stringvector 等组件代替原始指针和数组操作。

关联漏洞:

  • 高风险-内存破坏

7.3 【必须】避免大小端错误

在一些涉及大小端数据处理的场景,需要进行大小端判断,例如从大段设备取出的值,要以大段进行处理,避免端序错误使用。

关联漏洞:

  • 中风险-逻辑漏洞

7.4 【必须】检查除以零异常

在进行除法运算时,需要判断被除数是否为零,以防导致程序不符合预期或者崩溃。

错误:

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;
}

关联漏洞:

  • 低风险-拒绝服务

7.5 【必须】防止数字类型的错误强转

在有符号和无符号数字参与的运算中,需要注意类型强转可能导致的逻辑错误,建议指定参与计算时数字的类型或者统一类型参与计算。

错误例子

int Foo() {
  int len = 1;
  unsigned int size = 9;
  // 1 < 9 - 10 ? 由于运算中无符号和有符号混用,导致计算结果以无符号计算
  if (len < size - 10) {
    printf("Bad\n");
  } else {
    printf("Good\n");
  }
}

正确例子

void Foo() {
  // 统一两者计算类型为有符号
  int len = 1;
  int size = 9;
  if (len < size - 10) {
    printf("Bad\n");
  } else {
    printf("Good\n");
  }
}

关联漏洞:

  • 高风险-内存破坏

  • 中风险-逻辑漏洞

7.6 【必须】比较数据大小时加上最小/最大值的校验

在进行数据大小比较时,要合理地校验数据的区间范围,建议根据数字类型,对其进行最大和最小值的判断,以防止非预期错误。

错误:

void Foo(int index) {
  int a[30] = {0};
  // 此处index是int型,只考虑了index小于数组大小,但是并未判断是否大于0
  if (index < 30) {
    // 如果index为负数,则越界
    a[index] = 1;
  }
}

正确:

void Foo(int index) {
  int a[30] = {0};
  // 判断index的最大最小值
  if (index >=0 && index < 30) {
    a[index] = 1;
  }
}

关联漏洞:

  • 高风险-内存破坏
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号