




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、华为技术有限公司内部技术规范 C if (argc1 ) strcpy(dst,argv1);.dst 使用后 free.*/ 错误示例2 :典型的差一错误,未考虑 0结束符写入数组的位置,造成缓冲区溢岀和内存 改写。 void NoCompliant() char dstARRAY_SIZE+1; char srcARRAY_SIZE+1; unsignedint i=0; memset(src, , sizeof (dst); for (i=0;srci!= 0 +i) dsti=srci; dsti= O; /* .*/ 推荐做法: void Compliant() char dstAR
2、RAY_SIZE+1; char srcARRAY_SIZE+1; unsignedint i=0; memset(src, , sizeof (dst); for(i=0;srci!= 0 +i)/*【修改】考虑0 结束符 */ dsti=srci; dsti= 0; /* .*/ 规则:字符串操作过程中确保字符串有0结束符 说明:字符串结束与否是以o作为标志的。没有正确地使用o结束字符串可能导致字符 串操作时发生缓冲区溢出。因此对于字符串或字符数组的定义、设置、复制等操作,要给0 预留空间,并保证字符串有0结束符。 注意:str ncpy 、str neat等带n版本的字符串操作函数在源字
3、符串长度超岀n标识的长 度时,会将包括0结束符在内的超长字符串截断,导致0结束符丢失。这时需要手动为 目标字符串设置0结束符。 错误示例1 : strlen() 不会将0结束符算入长度,配合memcpy使用时会丢失0结束 符。 void Noncompliant() char dst11; char src=; char *tmp=NULL; memset(dst, , sizeof (dst); memcpy(dst,src,strlen(src); printf( src:%srn ,src); tmp=dst; int error_type=3; /*.dosomething.*/ pr
4、intf(Error(type%s):%dn,error_type,error_msg);/*【错误】格式化参数类 void Noncompliant_ArgMismatch() char *error_msg= Resourcenotavailabletouser.; int error_type=3; /*.dosomething.*/ printf(Error(type%s):%dn,error_msg,error_type);/*【修改】匹配格式化参 数类型*/ 错误示例2 :将结构体作为参数 void Noncompliant_StructAsArg() struct sParam
5、int num; char msg100; int result; ; struct sParamtmp=10, helloBaby! ,0; char *errormsg= Resourcenotavailabletouser.; int errortype=3; /*.dosomething.*/ if =0) printf(ErrorParam:%sn,tmp);/*【错误】不能将整个结构体作为格式化参数*/ 推荐做法: void Noncompliant_StructAsArg() struct sParam int num; char msg100; int result; ; st
6、ruct sParamtmp=10, helloBaby! ,0; char *errormsg= Resourcenotavailabletouser.; int errortype=3; /*.dosomething.*/ if =0) printf(ErrorParam:num=%d,msg=%s,result=%dn,; /*.dosomething.*/ printf(Error(type%s)n); /*.dosomething.*/ printf(Error(type%s)n,error_msg);.dosomething.*/ 推荐做法:优先采用snprintf 替代sprin
7、tf来防止缓冲区溢岀。若没有带n版本的 snprintf函数,可参考如下示例,使用spr intf,在接收字符串时,加上精度说明符,确 定接收的长度,以免造成缓冲区溢岀。 #define BUF_SIZE128 void Compliant。 char bufferBUF_SIZE+1; 字符串加上精度 sprintf(buffer,Usage:%.100sargumentn,argv0);/* 说明符*/ /*.dosomething.*/ 通过精度限制从argv0 中只能拷贝100个字节 3整数安全 C99标准定义了整型提升( in tegerpromotio ns )、整型转换级别 (i
8、n tegerc on versi onrank )以及普通算术转换(usualarithmeticc on versi ons )的 整型操作。不过这些操作实际上也带来了安全风险 规则:确保无符号整数运算时不会出现反转 说明:反转是指无法用无符号整数表示的运算结果将会根据该类型可以表示的最大值加 行求模操作。将运算结果用于以下之一的用途,应防止反转: 作为数组索引 指针运算 作为对象的长度或者大小 作为数组的边界 作为内存分配函数的实参 错误示例:下列代码可能导致相加操作产生无符号数反转现象。 INT32NoCompliant(UINT32ui1,UINT32ui2,UINT32*ret)
9、/*上面的代码可能会导致ui1加ui2产生无符号数反转现象,譬如ui1=UINT 这可能会导致后面的内存分配数量不足或者产生易被利用的潜在风险; MAX 且 ui2=2; */ return (OK); 推荐做法: INT32Compliant(UINT32ui1,UINT32ui2,UINT32*ret) return ERROR; if(UINT_MAX-ui1)ui2)/ return (allocnext=NULL; .dosomething.*/ returnmsg; .dosomething.*/ free(ptr); /*.dosomething.*/ free(ptr); .d
10、osomething.*/ free(ptr); ptr=NULL; /*.dosomething.*/ .申请的内存使用后free.*/ 推荐做法:调用malloc 之前,需要判断 malloc 的参数是否合法。确保 x为整数后才申请内 存,否则视为参数无效,不予申请,以避免岀现申请过大内存而导致拒绝服务。 int *Compliant( int x) int i; int *y; if(x0).申请的内存使用后 free.*/ 规则:禁止释放非动态申请的内存 说明:非动态申请的内存并不是由内存分配器管理的,如果使用free函数对这块内存进行释放, 会对内存分配器产生影响,造成拒绝服务。如果
11、黑客能控制非动态申请的内存内容,并对其进行 精心的构造,甚至导致程序执行任意代码。 错误示例:非法释放非动态申请的内存。 void Noncompliant() char str= thisisastring; /*.dosomething.*/ free(str);.dosomething.*/ /././etc/passwd ” 或 “./././” (2)构造指向系统关键文件的链接文件,例如symlink(/etc/shadow,/tmp/log) 通过上述两种方式之一可以实现读取或修改系统重要数据文件,威胁系统安全。 推荐做法: Lin ux下对文件进行标准化,可以防止黑客通过构造指向
12、系统关键文件的链接文件。realpath() 函数返回绝对路径,删除了所有符号链接: void Compliant( char *lplnputPath) char realpathMAX_PATH; if (realpath(inputPath,realpath)=NULL) /*handleerror*/; /*.dosomething.*/ Win dows下可以使用 PathCa noni calize函数对文件路径进行标准化: void Compliant( char *lpInputPath) char realpathMAX_PATH; char *lpRealPath=real
13、path; if ( PathCanonicalize(lpRealPath,lplnputPath)=NULL) /*handleerror*/; /*.dosomething.*/ 延伸阅读材料:披露了开源 HTTP服务器TinyServer存在目录遍历漏洞,可以允许攻击者 通过提交恶意 URL (如Server 的任意物理目录 建议:访问文件时尽量使用文件描述符代替文件名作为输入,以避免竞争条件问 题 说明:该建议应用场景如下,当对文件的元信息进行操作时(比如修改它的所有者、对文件进 行统计,或者修改它的权限位),首先要打开该文件,然后对打开的文件进行操作。只要有可能, 应尽量避免使用获
14、取文件名的操作,而是使用获取文件描述符的操作。这样做将避免文件在程序 运行时被替换(一种可能的竞争条件)。 例如,当access() 和open()两者都利用一个字符串参数而不是一个文件句柄来进行相关操作 时,攻击者就可以通过在access() 和open()之间的间隙替换掉原来的文件,如下所示: 行式打印 攻击者 access( ” /tmp/attack ”) unlink(” /tmp/attack ”) symlink( ” /etc/shadow ” , ” /tmp/attack ”) open( ” /tmp/attack ”) 错误示例:下列代码使用 access()函数,可能
15、引发竞争条件问题。 void Noncompliant( char *file) if(!access(file,W_OK).*/ | /*closefafteroperate(f)*/ else fprintf(stderr,Unabletoopenfile%s.n,file); 4 STL库安全 STL(StandardTemplateLibrary标准模板库)是C+开发中的常用组件,它通过容器+迭代 子+算法的灵活组合,可以满足很多应用场景,但使用不好则易留下安全隐患。 规则:引用容器前后元素时要确保容器元素存在 说明:没有判断是否为空就直接通过引用 STL容器首尾元素,这在容器为空时会
16、导致程序异常。 错误示例: bool NoCompliant( const NodeKeyList NodeKeysnkNode=(); /*.dosomething.*/ 示例代码对函数的入参srcList没有判断长度直接通过front() 和back()方法取了第一个和 最后一个元素,在容器列表为空的情况下,会导致程序异常,与fron t()类似的还有通过 begin()数据下标获取对应元素,比如*(),或者()-GetlD(),或者是srcList0( 在为 vector 时)。 推荐做法: bool Compliantconst NodeKeyList =DWDMTL1_ATTRPOR
17、T_CLIENTPRO; =it-; MAP_GENKEY_VALUE:iteratoriter=(tmpKey); if ( FC100 !=iter- . ; void SomeClass:destroy() /*.dosomething.*/ deletethis; .dosomething.*/ SomeClasssc; .dosomething.*/ ();. ; void SomeClass:destroy() /*.dosomething.*/ void main() SomeClasssc; .dosomething.*/ SomeClass() 如果不得不使用deleteth
18、is ,保证类对象是堆对象,且this 指针delete 考如下示例代码: class SomeClass public : SomeClass(); void doSomething(); void destroy。; protected : SomeClass(); ; void SomeClass:destroy() /*.dosomething.*/ deletethis ; SomeClass*sc= newSomeClass(); /*.dosomething.*/ sc-destroy(); sc=NULL; 这个示例代码中,将析构函数声明为protected ,可以保证类 So
19、meClass 生成。同时,在显示调用 destory() 来deletethis指针后,再将指针置 引用。 延伸阅读材料: 规则:禁止在类的公共接口中返回类的私有数据地址 说明:如果一个类私有成员数据的引用或者其指针,被类的公有函数作为返回值 此私有数据可能会遭受到非可信代码的修改,导致引入不安全因素。 例子1 : 错误示例:下列代码类中的私有成员变量被公共成员函数所引用。 class Widget public : Widget():total(O) .dosomething.*/ total+; /*.dosomething.*/ 后置NULL,可参 的对象不会在栈上 NULL,防止指针
20、解 return ,贝U void remove(someTypesomeParameters) /*.dosomething.*/ total-; /*.dosomething.*/ .dosomething.*/ total+; /*.dosomething.*/ void remove(someTypesomeParameters) /*.dosomething.*/ total-; /*.dosomething.*/ .*/ void f2() Tt; =50; ; int main() Aa; .*/ void f2() Tt; =50; ; templateclassA;.doso
21、mething.*/ r=rand(); .dosomething.*/ ID是可预测的并且随机性有很大限 文件来获取真随机数。 以上代码利用rand()产生一个ID的数字部分,因此这些 推荐做法:Unix/Linux下采取建议读取/dev/random void Compliant() enumlen=12; char idlen; /*idwillholdthelD,startingwith *thecharactersIDfollowedbya *randominteger*/ int r=0; int num; /*.dosomething.*/ int fd; fd= open(/d
22、ev/random,O_RDONLY); if (fd0) read(fd, /*generatearandomintegerfrom/dev/random*/ close(fd); num=snprintf(id,len,ID%-d,r); .dosomething.*/ Windows推荐使用随机数生成函数CryptGenRandom(): #include void Compliant() HCRYPTPROVhCryptProv; union BYTEbssizeof(longint); longint li; rand_buf; if (! CryptGenRandom(hCrypt
23、Prov,sizeof(rand_buf), 由于以上推荐的2种做法并不能保证主流编译环境下满足可靠性要求,对于可靠性要求很严格 的产品可以使用开源组件ope nssl或我司中研封装的iPSI组件: Open ssl示例: #include #include #include int Compliant() char buf20; constchar *p; unsignedchar outBuf20; char file50; int ret,len; BIO*bio_stdout; nd $HOMEisnotseteither,ornumistoosmallforthepath name,
24、anerroroccurs. */ p=RAND_file_name(file,sizeof(file); if (p=NULL) printf( cannotgetrandfilen); return -1; /* RAND_write_file()writesanumberofrandombytes(currently1024)to filefilenamewhichcanbeusedtoinitializethePRNGbycalling RAND_load_file()inalatersession. */ ret=RAND_write_file(p); n); return -1;
25、bio_stdout=BIO_new(BIO_s_file(); BIO_set_fp(bio_stdout,stdout,BIO_NOCLOSE); BIO_write(bio_stdout,outBuf,20); BIO_write(bio_stdout,n,2); BIO_free(bio_stdout); RAND_cleanup(); return 0; iPSI示例: #include void Compliant。 SEC_UCHARbuf100=0; CRYPT_random(buf,sizeof(buf);.*/ 规则:禁止存储getenv()返回的字符串指针 说明:gete
26、 nv()的返回指针指向值可能会被后续的gete nv()调用所覆盖,或者因为调用 pute nv()/sete nv()及其他办法修改了环境变量值而变得无效。存储该返回值可能会导致一 个危险的指针或者引用错误的数据,因此该返回的字符串应该被马上引用然后丢弃,如果需要在 后续使用该字符串,应该把该字符串拷贝到内存里,然后在需要的时候引用该份拷贝。 除此之外,gete nv()不是线程安全的,要确保处理使用该函数可能导致的竞争情况。 错误示例:下列代码错误的保存了gete nv()返回的字符串指针。 void Noncompliant() char *tmpvar=getenv( TMP); i
27、f (!tmpvar) return -1; char*tempvar=getenv(TEMP);.dosomething.*/ /*.dosomething.*/ /*.tempvar 使用后 free.*/ 规则:多线程环境下,禁止使用可能会导致crash的不安全函数 (1 )多线程环境下,禁止 std:cout 与printf 混用 说明:printf 与std:cout 分别为标准c语言与C+中的函数,两者的缓冲区机制不同 (pri ntf无缓冲区,而 std:cout 有),而且对于标准输岀的加锁时机也略有不同: printf:在对标准输岀作任何处理前先加锁; std:cout:在实
28、际向标准输岀打印时方才加锁; 二者存在微弱的时序差别,而多线程环境下, 很多问题就是由于微弱的时序差别造成的。所以两 者的混用很容易带来不可预知的错误,常见的错误有打印输岀的结果不符合预期,而严重错误时 甚至会导致内部缓存区溢出,导致crash 。 上面代码的输岀结果很可能为: 1 2 3 4 这很明显不符合程序员的预期。 造成这样错误的原因就是 std:cout的标准流输岀是带有缓冲 区的,如果没有及时清理缓冲区而在期间采用了其它系统的输岀函数,可能会暴露两种输岀函数 的不兼容性,从而出现非预期错误。所以建议在代码中检查对于系统标准打印输出的兼容性,一 定要使用统一的打印输岀方法 ,而对于C
29、+程序,更推荐统一使用流输岀方法,而不推荐使用C 风格的代码。 推荐做法: void Compliant。 int j=0; for (j=0;j5;+j) printf(j=); printf(%dn,j);【修改】只用 printf 或者 void Compliant。 int j=0; for (j=0;j5;+j) coutvvj=; cout #define LINE_DELIMITERSn #define WORD_DELIMITERS staticint wordcount_Nocompliant(char *s) int coutn=1; if(strtok(s,WORD_DE
30、LIMITERS)=NULL)/*【错误】多线程环境下使用strtok 会出现 crash*/ return 0; while(strtok(NULL,WORD_DELIMITERS)!=NULL) count+; return count; double wordaverage_Nocompliant(char *s) int linecount=1; char *nextline; int words; nextline=strtok(s,LINE_DELIMITERS); if (nextline=NULL) words=wordcount(nextline); while(nextli
31、ne=strtok(NULL ,L INE_DELIMITERS)!=NULL) words+=wordcount(nextline); linecount+; return (double )words/linecount; 推荐做法:带有的函数主要来自于UNIX下面。所有的带有和不带的函数的区别的是: 带的函数是线程安全的,r的意思是reentrant,可重入的。 #include #define LINE_DELIMITERSn #define WORD_DELIMITERS staticint wordcount_Compliant( char *s) int coutn=1; cha
32、r *lasts; if(strtok_r(s,WORD_DELIMITERS, while(strtok_r(NULL,WORD_DELIMITERS, return count; double wordaverage_Compliant(char *s) int linecount=1; char *nextline; int words; char *lasts; nextline=strtok_r(s 丄 INE_DELIMITERS, if (nextline=NULL) words=wordcount(nextline); while(nextline=strtok_r(NULL
33、,L INE_DELIMITERS, linecount+; return (double )words/linecount; 建议:编译时应当使用编译器的最高警告等级 说明:程序员应当使用编译器的最高警告等级。在编译过程中,应该修改程序中的错误,直到警 告解除。在此同时,应当使用静态和动态的分析工具来检测和清除安全缺陷。 另外,开启一些和安全相关的编译选项,可以使编译岀来的程序具有更好的安全特性。 对于GCC编译器,建议开启以下安全选项: (1 )使用PIE选项(gcc-fPIE/ld-pie),可以将源代码编译成和位置无关的可执行程序。 (2)使用-fstack-protector-all
34、或-fstack-protector选项,通过栈保护, 来防止程 序出现缓冲区溢出错误。 对于VC (VS2005及以上的版本)编译器,可以开启如下和安全相关的编译选项: (1 ) GS (栈保护):通过在栈中加入校验单元来防止岀现缓冲区溢岀错误。 (2 ) NXCOMPAT (与数据执行保护兼容):DEP,也就是数据执行保护,可以有效降低堆或栈 上的缓存溢岀漏洞的危害性。采用NXCOMPAT选项后,应用程序的运行被DEP机制保护。在考 虑兼容性的前提下,建议开发人员采用NXCOMPAT链接选项。 (3 ) ASLR (地址空间分布随机):是一种针对缓冲区溢岀的安全保护技术,通过对堆、栈、共
35、享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻 击代码位置,达到阻止溢出攻击的目的。 建议:防止处理敏感数据的代码因被编译器优化而失效 说明:有时候编译器在优化时会删除一些它认为不必要的代码,但实际这些看似多余的代码是存 在安全考虑。一个典型的例子就是函数返回前清除栈上敏感数据的操作,如果这些操作被删除掉, 攻击者就有机会访问栈上的敏感数据。因此必须确保这些安全操作在编译器优化的场景下仍然得 以执行。 错误示例: 下列代码使用了可能被编译器优化掉的语句。 void Noncompliant() char pwd64; if (retrievePassword(pwd,sizeof (pwd) /*checkingofpassword,secureoperations,etc*/ memset(pwd,0,sizeof(pwd);/【错误】
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 枇杷水彩画课件
- 全国安全生产应急知识竞赛试题及答案
- 护士执业资格考试辅导-神经系统疾病病人的护理知识点考试题库及答案-执业护士
- 2025麻精药品培训考试试题(含答案)
- 安全培训的实施效果课件
- DB6105T 129-2020 养老机构入住评估服务规范
- 2025驾驶员考试危险品运输员模拟试卷及答案
- 十八项医疗核心制度必考试题库及答案
- 护理核心制度考试试题(含答案)
- 电力安全应急知识题库及答案
- 2025年市级科技馆招聘笔试重点
- 2025年度房屋拆迁补偿安置房买卖协议
- 2025西电考试题及答案
- 南昌市小学二年级 2025-2026 学年数学秋季开学摸底测试卷(人教版)含解读答案
- 2025年先兆流产的护理查房
- 电子竞技赛事策划与组织运营管理方案设计
- 人教版(2024)八年级上册数学全册教案
- 2025年智慧城市信息化运维服务合作合同模板
- 职工职业健康体检实施方案与标准
- 2025年部编版新教材语文九年级上册教学计划(含进度表)
- 2025年多省公务员联考公安基础知识考试真题(附答案)
评论
0/150
提交评论