安全编码一些建议

Posted by 周思进 on February 16, 2020

想要编写安全的代码,首先就是要有安全意识。有了安全意识后平常再多积累安全编码注意事项,就可以避免可能存在的安全漏洞。

1、了解调用接口
不说要掌握各系统调用接口或者库函数接口,但对于自己编写的代码,所调用到的接口一定要心里清楚入参、出参及函数可能的返回值处理,比如注意不同接口对于表示成功的返回值是不一样的,有些可能返回0是成功,有些返回1才表示成功等等。
经常遇到的一些库函数使用错误的接口比如字符串相关处理函数,如strcpy、strcat、sprintf都应该使用相对安全的strncpy、strncat、snprintf等等。

2、入参合法性检测
不是每个人都会明确函数入参的取值范围,所以函数接口只要是会提供给他人调用的,都需要对入参合法性做检测,确保所传入的数据是可信任的,尤其是由外部传入的数据。

最基本的就是指针判空处理、值的范围判断(需要注意变量类型是否合理,是否可能溢出)。
然后就是对传递的内容本身进行合法性判断,比如字符串是否存在一些非法字符,文件内容长度、格式等是否匹配,如图片、视频、证书等等。
还有比如网络传输,可能需要动态分配一块内存来存储后续需要接受的数据,对端发送后续数据长度过来,接收方以此申请对应长度内存,这个就要注意申请的内存长度是否异常。

当然数据可能是一层层传递下来的,或者通过多个协议传递过来的,是在所有经过的接口都做判断还是只在最终底层处理数据的那个接口做检测处理这个我也不好明确。个人觉得最终底层处理接口可能会被不同协议处理调用,因此在最终底层处理数据那个接口做入参合法性检测是有必要的。

3、函数返回值
确认函数返回值是否是局部变量,如果是局部变量,函数返回后,该局部变量在内存中的值可能已不存在,那获取的结果就不是正确的结果信息。

4、入参是否可能发生变化
这个和上面那点差不多,需要确认入参在函数执行过程中是否可能发生变化。比如调用的接口是异步执行的,而原有传入的入参对于调用方也是局部变量,当调用方先执行完导致释放了该局部变量,这类情况也需要注意。
不是上面那种情况,也需要注意是否在调用的过程中,外部会对其进行更改,尤其是一些全局共享变量。

5、变量赋初值
对于声明的变量,一定要记得赋初值,即声明的时候就进行初始化操作(基本也就是清零操作),否则很有可能后面赋值后的变量值并不是真实想要的值,尤其是字符串这类没有\0结尾导致的一些越界行为。
如果是后续要申请内存的指针变量,则初始指向NULL,等后面真实需要分配内存使用了再进行动态内存分配。

6、接口可重入
确认编写的接口是否存在多线程调用的情况,如果存在,该接口是否做到可重入,如果不是,那就需要修改,大部分情况可能是需要加锁进行互斥保护,对于锁的粒度应该尽可能的小,只在共享资源操作前后加锁保护即可。
对于函数内部有使用到局部静态变量的,尤其需要多注意下。
另外是否要起线程,也应该要考虑下,我是看到过只是单纯调用下接口马上执行完的那种,都有起线程来调用的。

7、内容拷贝
对于外部传入一个内存地址,由接口内部进行拷贝赋值,一定要传递对应内存的长度大小进来,看到有太多接口因为没有大小入参,后面出问题的。

8、异常处理
任何处理流程都应该考虑如果失败情况下应该怎么执行处理。

9、避免频繁动态申请、释放内存
一个用户操作就会动态申请、释放内存,就要考虑如果该操作可以频繁执行,那就会频繁的动态申请和释放内存,这就可能导致大量内存碎片,这对于内存比较紧张的嵌入式设备极有可能后面就OOM了。
对此需要注意内存是否一定要动态申请,如果一定要动态申请,申请的大小是否合理。