




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、華為技術(shù)部技術(shù)規(guī)DKBA 6914-2013.05C&C+語言安全編程規(guī)2013年05月07日發(fā)布 2013年05月07日實施華為技術(shù)Huawei Technologies Co., Ltd.所有 侵權(quán)必究修訂聲明本規(guī)擬制與解釋部門: 網(wǎng)絡(luò)安全技術(shù)能力中心本規(guī)的相關(guān)系列規(guī)或文件: Java語言安全編程規(guī)Web應(yīng)用安全開發(fā)規(guī)相關(guān)國際規(guī)或文件一致性: 無替代或作廢的其它規(guī)或文件: 無相關(guān)規(guī)或文件的相互關(guān)系:本規(guī)作為C語言編程規(guī)和C+語言編程規(guī)安全性要求的補充和擴展。規(guī)號主要起草部門專家主要評審部門專家修訂情況DKBA6914-2013.05網(wǎng)絡(luò)安全能力中心:羅東 67107、 于鵬 900
2、06799、苗宏 90006736、朱喜紅 00210657電信軟件與核心網(wǎng):輝軍 00190784無線產(chǎn)品線:肖飛龍 00051938網(wǎng)絡(luò)產(chǎn)品線:建雄 00222905IT產(chǎn)品線:熊華梁00106214中央軟件院:朱楚毅00217543、林水平 00109837、周強 00048368、辛威 00176185、鞠章蕾 00040951、青 00101378中央硬件院:永合00222758終端公司:棋斌 00060469企業(yè)網(wǎng)絡(luò):黃凱進 00040281、企業(yè)SecoSpace:王瑾 90003828中央軟件院:黃茂青 00057072、盧峰 00210300網(wǎng)絡(luò)產(chǎn)品線:強 00203020、
3、羅天 00062283、廖永強 00111217、任志清 00048956、海蛟 00040826、璟 00222879、勾國凱 00048893、佳甲 00109753中央硬件院:崇山 00159994、施文超 00109740企業(yè)網(wǎng)絡(luò):有永 90002701IT產(chǎn)品線:顯才 00044635、何昌軍 00061280能力中心:郭曙光 00121837網(wǎng)絡(luò)安全實驗室:林結(jié)斌 00206214電信軟件與核心網(wǎng):朱剛 00192988無線產(chǎn)品線:瀛 00130531、王愛成 00223009、彬 00065941、于繼萬 00052142、解然 00234688V1.0目 錄 C&C+語
4、言安全編程規(guī)1C&C+語言安全編程規(guī)60規(guī)制定說明60.1前言60.2使用對象60.3適用圍60.4術(shù)語定義61通用原則7原則1.1:對外部輸入進行校驗7原則1.2:禁止在日志中保存口令、密鑰8原則1.3:及時清除存儲在可復(fù)用資源中的敏感信息8原則1.4:正確使用經(jīng)過驗證的安全的標(biāo)準加密算法8原則1.5:遵循最小權(quán)限原則9原則1.6:刪除或修改沒有效果的代碼9原則1.7:刪除或修改沒有使用到的變量或值92字符串操作安全10規(guī)則2.1:確保有足夠的空間存儲字符串的字符數(shù)據(jù)和0結(jié)束符10規(guī)則2.2:字符串操作過程中確保字符串有0結(jié)束符11規(guī)則2.3:把數(shù)據(jù)復(fù)制到固定長度的存前必須檢查邊界1
5、3規(guī)則2.4:避免字符串/存操作函數(shù)的源指針和目標(biāo)指針指向存重疊區(qū)133格式化輸出安全15規(guī)則3.1:格式化輸出函數(shù)的格式化參數(shù)和實參類型必須匹配15規(guī)則3.2:格式化輸出函數(shù)的格式化參數(shù)和實參個數(shù)必須匹配17規(guī)則3.3:禁止以用戶輸入來構(gòu)造格式化字符串17建議3.1:使用格式化函數(shù)時推薦使用精度說明符184整數(shù)安全19規(guī)則4.1:確保無符號整數(shù)運算時不會出現(xiàn)反轉(zhuǎn)19規(guī)則4.2:確保有符號整數(shù)運算時不會出現(xiàn)溢出20規(guī)則4.3:確保整型轉(zhuǎn)換時不會出現(xiàn)截斷錯誤21規(guī)則4.4:確保整型轉(zhuǎn)換時不會出現(xiàn)符號錯誤22規(guī)則4.5:把整型表達式比較或賦值為一種更大類型之前必須用這種更大類型對它進行求值23建議
6、4.1:避免對有符號整數(shù)進行位操作符運算235存管理安全24規(guī)則5.1:禁止引用未初始化的存24規(guī)則5.2:禁止訪問已經(jīng)釋放的存25規(guī)則5.3:禁止重復(fù)釋放存27規(guī)則5.4:必須對指定申請存大小的整數(shù)值進行合法性校驗27規(guī)則5.5:禁止釋放非動態(tài)申請的存29建議5.1:避免使用alloca函數(shù)申請存296禁用不安全函數(shù)或?qū)ο?0規(guī)則6.1:禁止使用未顯式指明目標(biāo)緩沖區(qū)大小的字符串操作函數(shù)30規(guī)則6.2:禁止調(diào)用OS命令解析器執(zhí)行命令或運行程序,防止命令注入32規(guī)則6.3:禁止使用std:ostrstream,推薦使用std:ostringstream33規(guī)則6.4:C+中,必須使用C+標(biāo)準庫替
7、代C的字符串操作函數(shù)337文件輸入/輸出安全35規(guī)則7.1:必須使用int類型來接收字符輸入/輸出函數(shù)的返回值35規(guī)則7.2:創(chuàng)建文件時必須顯式指定合適的文件訪問權(quán)限36規(guī)則7.3:文件路徑驗證前,必須對其進行標(biāo)準化36建議7.1:訪問文件時盡量使用文件描述符代替文件名作為輸入,以避免競爭條件問題378STL庫安全38規(guī)則8.1:引用容器前后元素時要確保容器元素存在38規(guī)則8.2:迭代子使用前必須保證迭代子有效39規(guī)則8.3:必須確保迭代子指向的容有效40規(guī)則8.4:正確處理容器的erase()方法與迭代子的關(guān)系419C+類和對象安全42規(guī)則9.1:禁止切分多態(tài)的類對象42規(guī)則9.2:禁止定義
8、基類析構(gòu)函數(shù)為非虛函數(shù),所有可能被繼承類的析構(gòu)函數(shù)都必須定義為virtual44規(guī)則9.3:避免出現(xiàn)delete this操作46規(guī)則9.4:禁止在類的公共接口中返回類的私有數(shù)據(jù)地址48建議9.1:重載后綴操作符應(yīng)返回const類型49建議9.2:顯式聲明的模板類應(yīng)進行類型特化5010其它51規(guī)則10.1:禁止使用rand()產(chǎn)生用于安全用途的偽隨機數(shù)51規(guī)則10.2:禁止存儲getenv()返回的字符串指針55規(guī)則10.3:多線程環(huán)境下,禁止使用可能會導(dǎo)致crash的不安全函數(shù)56建議10.1:編譯時應(yīng)當(dāng)使用編譯器的最高警告等級60建議10.2:防止處理敏感數(shù)據(jù)的代碼因被編譯器優(yōu)化而失效60
9、11參考資料62C&C+語言安全編程規(guī)0 規(guī)制定說明0.1 前言隨著公司業(yè)務(wù)發(fā)展,越來越多的產(chǎn)品被公眾、互聯(lián)網(wǎng)所熟知,并成為安全研究組織的研究對象、黑客的漏洞挖掘目標(biāo),容易引起安全問題。安全問題影響的不只是單個產(chǎn)品,甚至有可能影響到公司整體聲譽。產(chǎn)品安全涉及需求、設(shè)計、實現(xiàn)、部署多個環(huán)節(jié),實現(xiàn)的安全是產(chǎn)品安全的重要一環(huán)。為了幫助產(chǎn)品開發(fā)團隊編寫安全的代碼,減少甚至規(guī)避由于編碼錯誤引入安全風(fēng)險,特制定本規(guī)。C&C+語言安全編程規(guī)參考業(yè)界安全編碼的研究成果,并結(jié)合產(chǎn)品編碼實踐的經(jīng)驗總結(jié),針對C/C+語言編程中的字符串操作、整數(shù)操作、存管理、文件操作、STL庫使用等方面,描述可能導(dǎo)致
10、安全漏洞或潛在風(fēng)險的常見錯誤。以期減少緩沖區(qū)溢出、整數(shù)溢出、格式化字符串攻擊、命令注入攻擊、目錄遍歷等典型安全問題。0.2 使用對象本規(guī)的讀者及使用對象主要為使用C和C+語言的開發(fā)人員、測試人員等。0.3 適用圍本規(guī)適合于公司基于C或C+語言開發(fā)的產(chǎn)品。0.4 術(shù)語定義原則: 編程時必須遵守的指導(dǎo)思想。規(guī)則:編程時必須遵守的約定。建議:編程時必須加以考慮的約定。說明:對此原則/規(guī)則/建議進行必要的解釋。錯誤示例:對此原則/規(guī)則/建議從反面給出例子。推薦做法:對此原則/規(guī)則/建議從正面給出例子。延伸閱讀材料:建議進一步閱讀的參考材料。1 通用原則原則1.1:對外部輸入進行校驗說明:對于外部輸入(
11、包括用戶輸入、外部接口輸入、配置文件、網(wǎng)絡(luò)數(shù)據(jù)和環(huán)境變量等)可能用于以下場景的情況下,需要檢驗入?yún)⒌暮戏ㄐ裕簂 輸入會改變系統(tǒng)狀態(tài)l 輸入作為循環(huán)條件l 輸入作為數(shù)組下標(biāo)l 輸入作為存分配的尺寸參數(shù)l 輸入作為格式化字符串l 輸入作為業(yè)務(wù)數(shù)據(jù)(如作為命令執(zhí)行參數(shù)、拼裝sql語句、以特定格式持久化)l 輸入影響代碼邏輯這些情況下如果不對用戶數(shù)據(jù)作合法性驗證,很可能導(dǎo)致DoS、存越界、格式化字符串漏洞、命令注入、SQL注入、緩沖區(qū)溢出、數(shù)據(jù)破壞等問題。對外部輸入驗證常見有如下幾種方式:(1)校驗輸入數(shù)據(jù)長度:如果輸入數(shù)據(jù)是字符串,通過校驗輸入數(shù)據(jù)的長度可以加大攻擊者實施攻擊的難度,從而防止緩沖區(qū)溢
12、出、惡意代碼注入等漏洞。(2)校驗輸入數(shù)據(jù)的圍:如果輸入數(shù)據(jù)是數(shù)值,必須校驗數(shù)值的圍是否正確,是否合法、在有效值域,例如在涉及到存分配、數(shù)組操作、循環(huán)條件、計算等安全操作時,若沒有進行輸入數(shù)值有效值域的校驗,則可能會造成存分配失敗、數(shù)組越界、循環(huán)異常、計算錯誤等問題,這可能會被攻擊者利用并進行進一步的攻擊。(3)輸入驗證前,對數(shù)據(jù)進行歸一化處理以防止字符轉(zhuǎn)義繞過校驗:通過對輸入數(shù)據(jù)進行歸一化處理(規(guī)化,按照常用字符進行編碼),徹底去除元字符,可以防止字符轉(zhuǎn)義繞過相應(yīng)的校驗而引起的安全漏洞。(4)輸入校驗應(yīng)當(dāng)采用“白”形式:“黑”和“白”是進行數(shù)據(jù)凈化的兩種途徑?!昂凇眹L試排斥無效的輸入,而“白
13、”則通過定義一個可接受的字符列表,并移除任何不接受的字符來僅僅接受有效的輸入。有效輸入值列表通常是一個可預(yù)知的、定義良好的集合,并且其大小易于管理?!鞍住钡暮锰幵谟冢绦騿T可以確定一個字符串中僅僅包含他認為安全的字符?!鞍住北取昂凇备芡扑]的原因是,程序員不必花力氣去捕捉所有不可接受的字符,只需確保識別了可接受的字符就可以了。這樣一來,程序員就不用絞盡腦汁去考慮攻擊者可能嘗試哪些字符來繞過檢查。原則1.2:禁止在日志中保存口令、密鑰說明:在日志中不能保存口令和密鑰,其中的口令包括明文口令和密文口令。對于敏感信息建議采取以下方法,l 不打印在日志中;l 若因為特殊原因必須要打印日志,則用“*”代
14、替。原則1.3:及時清除存儲在可復(fù)用資源中的敏感信息說明:存儲在可復(fù)用資源中的敏感信息如果沒有正確的清除則很有可能被低權(quán)限用戶或者攻擊者所獲取和利用。因此敏感信息在可復(fù)用資源中保存應(yīng)該遵循存儲時間最短原則。可復(fù)用資源包括以下幾個方面:l 堆(heap)l 棧(stack)l 數(shù)據(jù)段(data segment)l 數(shù)據(jù)庫的映射緩存存儲口令、密鑰的變量使用完后必須顯式覆蓋或清空。原則1.4:正確使用經(jīng)過驗證的安全的標(biāo)準加密算法說明:禁用私有算法或者弱加密算法(如DES,SHA1等),應(yīng)該使用經(jīng)過驗證的、安全的、公開的加密算法。加密算法分為對稱加密算法和非對稱加密算法。推薦使用的常用對稱加密算法有:
15、l AES推薦使用的常用非對稱算法有:l RSAl 數(shù)字簽名算法(DSA)此外還有驗證消息完整性的安全哈希算法(SHA256)等?;诠K惴ǖ目诹畎踩鎯Ρ仨毤尤臌}值(salt)。密鑰長度符合最低安全要求:l AES: 128位l RSA: 2048位l DSA: 1024位l SHA: 256位原則1.5:遵循最小權(quán)限原則說明:程序在運行時可能需要不同的權(quán)限,但對于某一種權(quán)限不需要始終保留。例如,一個網(wǎng)絡(luò)程序可能需要超級用戶權(quán)限來捕獲原始網(wǎng)絡(luò)數(shù)據(jù)包,但是在執(zhí)行數(shù)據(jù)報分析等其它任務(wù)時,則可能不需要相同的權(quán)限。因此程序在運行時只分配能完成其任務(wù)的最小權(quán)限。過高的權(quán)限可能會被攻擊者利用并進行進一
16、步的攻擊。(1)撤銷權(quán)限時應(yīng)遵循正確的撤銷順序:在涉及到set-user-ID和set-group-ID程序中,當(dāng)有效的用戶ID(user ID)和組ID(group ID)與真實的用戶不同時,不但要撤銷用戶層面(user level)的權(quán)限而且要撤銷組層面(group level)的權(quán)限。在進行這樣的操作時,要保證撤銷順序的正確性。權(quán)限撤銷順序的不正確操作,可能會被攻擊者獲得過高的權(quán)限而進行進一步的攻擊。(2) 完成權(quán)限撤銷操作后,應(yīng)確保權(quán)限撤銷成功:不同平臺下所謂的“適當(dāng)?shù)臋?quán)限”的意義是不相同的。例如在Solaris中,setuid()的適當(dāng)?shù)臋?quán)限指的是PRIV_PROC_SETID權(quán)限在
17、進程的有效權(quán)限集中。在BSD中意味著有效地用戶ID(EUID)為0或者uid=geteuid()。而在Linux中,則是指進程具有CAP_SETUID能力并且當(dāng)EUID不等于0、真正的用戶ID(RUID)或者已保存的set-user ID(SSUID)中任何一個時,setuid(geteuid()是失敗的。正是由于權(quán)限行為的復(fù)雜性,所以所需的權(quán)限在撤銷時可能會失敗。這會被攻擊者利用并進行進一步的攻擊。例如Kernel版本在2.2.0-2.2.15的Linux就有一個權(quán)限撤銷漏洞,當(dāng)權(quán)限功能位置為0時,setuid(getuid()沒有如預(yù)期的那樣撤銷權(quán)限成功。因此在進行權(quán)限撤銷操作后,應(yīng)該校驗
18、以保證權(quán)限撤銷成功。原則1.6:刪除或修改沒有效果的代碼說明:刪除或修改一些即使執(zhí)行后、也不會有任何效果的代碼。一些存在的代碼(聲明或表達式),即使它被執(zhí)行后,也不會對代碼的結(jié)果或數(shù)據(jù)的狀態(tài)產(chǎn)生任何的影響,或者產(chǎn)生不是所預(yù)期的效果,這樣的代碼在可能是由于編碼錯誤引起的,往往隱藏著邏輯上的錯誤。原則1.7:刪除或修改沒有使用到的變量或值說明:刪除或修改沒有使用到的變量或值。一些變量或值存在于代碼里,但并沒有被使用到,這可能隱含著邏輯上的錯誤,需要被識別出來,刪除這類語句或做相應(yīng)的修改。2 字符串操作安全規(guī)則2.1:確保有足夠的空間存儲字符串的字符數(shù)據(jù)和0結(jié)束符說明:在分配存或者在執(zhí)行字符串復(fù)制操
19、作時,除了要保證足夠的空間可以容納字符數(shù)據(jù),還要預(yù)留0結(jié)束符的空間,否則會造成緩沖區(qū)溢出。錯誤示例1:拷貝字符串時,源字符串長度可能大于目標(biāo)數(shù)組空間。void main(int argc, char *argv)char dst128;if ( argc > 1 )strcpy(dst, argv1); / 源字符串長度可能大于目標(biāo)數(shù)組空間,造成緩沖區(qū)溢出/*/ 推薦做法:根據(jù)源字符串長度來為目標(biāo)字符串分配空間。void main(int argc, char *argv)char *dst = NULL;if ( argc > 1 )dst = (char *)malloc(st
20、rlen(argv1) + 1); /* 【修改】確保字符串空間足夠容納argv1 */if( dst != NULL )strncpy(dst, argv1, strlen(argv1);dststrlen(argv1) = 0; /【修改】dst以0結(jié)尾/*.dst使用后free.*/ 錯誤示例2:典型的差一錯誤,未考慮0結(jié)束符寫入數(shù)組的位置,造成緩沖區(qū)溢出和存改寫。void NoCompliant()char dstARRAY_SIZE + 1;char srcARRAY_SIZE + 1;unsigned int i = 0;memset(src, '', sizeof
21、(dst);for(i=0; srci != 0 && (i < sizeof(dst); +i )dsti = srci;dsti = 0; /*/ 推薦做法:void Compliant()char dstARRAY_SIZE + 1;char srcARRAY_SIZE + 1;unsigned int i = 0;memset(src, '', sizeof(dst);for(i=0; srci!=0 && (i < sizeof(dst) - 1 ); +i) /*【修改】考慮0結(jié)束符 */dsti = srci;dsti
22、= 0; /*/ 規(guī)則2.2:字符串操作過程中確保字符串有0結(jié)束符說明:字符串結(jié)束與否是以0作為標(biāo)志的。沒有正確地使用0結(jié)束字符串可能導(dǎo)致字符串操作時發(fā)生緩沖區(qū)溢出。因此對于字符串或字符數(shù)組的定義、設(shè)置、復(fù)制等操作,要給0預(yù)留空間,并保證字符串有0結(jié)束符。注意:strncpy、strncat等帶n版本的字符串操作函數(shù)在源字符串長度超出n標(biāo)識的長度時,會將包括0結(jié)束符在的超長字符串截斷,導(dǎo)致0結(jié)束符丟失。這時需要手動為目標(biāo)字符串設(shè)置0結(jié)束符。錯誤示例1:strlen()不會將0結(jié)束符算入長度,配合memcpy使用時會丟失0結(jié)束符。void Noncompliant()char dst11;cha
23、r src = "0123456789"char *tmp = NULL;memset(dst, '', sizeof(dst); memcpy(dst, src, strlen(src);printf("src: %s rn", src);tmp = dst; /到此,dst還沒有以0結(jié)尾doputchar(*tmp);while (*tmp+); / 訪問越界return; 推薦做法: 為目標(biāo)字符串設(shè)置0結(jié)束符void Compliant()char dst11;char src = "0123456789"cha
24、r *tmp = NULL;memset(dst, '', sizeof(dst);memcpy(dst, src, strlen(src);dstsizeof(dst) - 1 = 0; /【修改】dst以0結(jié)尾printf("src: %s rn", src);tmp = dst;doputchar(*tmp); while (*tmp+);return; 錯誤示例2:strncpy()拷貝限長字符串,截斷了0結(jié)束符。 void Noncompliant()char dst5;char src = "0123456789"strncp
25、y(dst, src, sizeof(dst); printf(dst); /訪問越界,dst沒有0結(jié)束符return;推薦做法: void Compliant()char dst5; char src = "0123456789"strncpy(dst, src, sizeof(dst);dstsizeof(dst)-1 = 0; / 【修改】最后字節(jié)置為0 printf(dst); return;規(guī)則2.3:把數(shù)據(jù)復(fù)制到固定長度的存前必須檢查邊界說明:將未知長度的數(shù)據(jù)復(fù)制到固定長度的存空間可能會造成緩沖區(qū)溢出,因此在進行復(fù)制之前應(yīng)首先獲取并檢查數(shù)據(jù)長度。典型的如來自ge
26、ts()、getenv()、scanf()的字符串。錯誤示例:輸入消息長度不可預(yù)測,不加檢查的復(fù)制會造成緩沖區(qū)溢出。void Noncompliant()char dst16;char * temp = getInputMsg();if(temp != NULL)strcpy(dst,temp); / temp長度可能超過dst的大小return; 推薦做法: void Compliant()char dst16;char *temp = getInputMsg();if(temp != NULL)strncpy(dst, temp, sizeof(dst); /* 【修改】只復(fù)制不超過數(shù)組d
27、st大小的數(shù)據(jù) */dstsizeof(dst) -1 = 0; /【修改】copy以0結(jié)尾return;規(guī)則2.4:避免字符串/存操作函數(shù)的源指針和目標(biāo)指針指向存重疊區(qū)說明:存重疊區(qū)是指一段確定大小及地址的存區(qū),該存區(qū)被多個地址指針指向或引用,這些指針介于首地址和尾地址之間。在使用像memcpy、strcpy、strncpy、sscanf()、sprintf()、snprintf()和wcstombs()這樣的函數(shù)時,復(fù)制重疊對象會存在未定義的行為,這種行為可能破壞數(shù)據(jù)的完整性。錯誤示例1:snprintf的參數(shù)使用存在問題void Noncompliant()#define MAX_LEN
28、 1024char cBufMAX_LEN + 1 = 0;int nPid = 0;strncpy(cBuf, ”Hello World!”, strlen(”Hello World!”);snprintf(cBuf, MAX_LEN, "%d: %s", nPid, cBuf); /* cBuf既是源又是目標(biāo),函數(shù)使用不安全 */return; 推薦做法:使用不同源和目標(biāo)緩沖區(qū)來實現(xiàn)復(fù)制功能。void Compliant()#define MAX_LEN 1024char cBufMAX_LEN + 1 = 0;char cDescMAX_LEN + 1 = 0; /【
29、修改】另起一個緩沖區(qū),防止緩沖區(qū)重疊出錯int nPid = 0;strncpy(cDesc, ”Hello World!”, strlen(”Hello World!”); /* 【修改】防止緩沖區(qū)重疊出錯 */snprintf(cBuf, MAX_LEN, "%d: %s", nPid, cDesc); /* 【修改】防止緩沖區(qū)重疊出錯 */return;錯誤示例2:#define MSG_OFFSET 3#define MSG_SIZE 6void NoCompliant ()char str = "test string"char *ptr1 =
30、 str;char *ptr2;ptr2 = ptr1+MSG_OFFSET;memcpy(ptr2, ptr1, MSG_SIZE);return;推薦做法:使用memmove函數(shù),源字符串和目標(biāo)字符串所指存區(qū)域可以重疊,但復(fù)制后目標(biāo)字符串容會被更改,該函數(shù)將返回指向目標(biāo)字符串的指針。#define MSG_OFFSET 3#define MSG_SIZE 6void Compliant ()char str = "test string"char *ptr1 = str;char *ptr2;ptr2 = ptr1 + MSG_OFFSET;memmove(ptr2,
31、ptr1, MSG_SIZE); /*【修改】使用memmove代替memcpy,防止緩沖區(qū)重疊出錯 */return;memcpy與memmove的目的都是將N個字節(jié)的源存地址的容拷貝到目標(biāo)存地址中。但當(dāng)源存和目標(biāo)存存在重疊時,memcpy會出現(xiàn)錯誤,而memmove能正確地實施拷貝,但這也增加了一點點開銷。memmove的處理措施:l 當(dāng)源存的首地址等于目標(biāo)存的首地址時,不進行任何拷貝l 當(dāng)源存的首地址大于目標(biāo)存的首地址時,實行正向拷貝l 當(dāng)源存的首地址小于目標(biāo)存的首地址時,實行反向拷貝3 格式化輸出安全規(guī)則3.1:格式化輸出函數(shù)的格式化參數(shù)和實參類型必須匹配說明:使用格式化字符串應(yīng)該小心
32、,確保格式字符和參數(shù)在數(shù)據(jù)類型上的匹配。格式字符和參數(shù)之間的不匹配會導(dǎo)致未定義的行為。大多數(shù)情況下,不正確的格式化字符串會可能會導(dǎo)致格式化漏洞,使程序異常終止。錯誤示例1:格式字符和參數(shù)的類型不匹配void Noncompliant_ArgMismatch()char *error_msg = "Resource not available to user."int error_type = 3; /* .do something. */printf("Error (type %s): %dn", error_type, error_msg); /*【錯
33、誤】格式化參數(shù)類型不匹配 */推薦做法: void Noncompliant_ArgMismatch()char *error_msg = "Resource not available to user."int error_type = 3; /* .do something. */printf("Error (type %s): %dn", error_msg, error_type); /*【修改】匹配格式化參數(shù)類型 */錯誤示例2:將結(jié)構(gòu)體作為參數(shù)void Noncompliant_StructAsArg()struct sParam int n
34、um; char msg100; int result; ; struct sParam tmp = 10, "hello Baby!", 0; char *errormsg = "Resource not available to user." int errortype = 3;/* .do something. */if (tmp.result = 0) printf("Error Param: %s n", tmp); /*【錯誤】不能將整個結(jié)構(gòu)體作為格式化參數(shù) */ 推薦做法: void Noncompliant_Struc
35、tAsArg()struct sParam int num; char msg100; int result; ; struct sParam tmp = 10, "hello Baby!", 0; char *errormsg = "Resource not available to user." int errortype = 3;/* .do something. */if (tmp.result = 0) printf("Error Param:num=%d, msg=%s, result=%dn", tmp.num, tmp
36、.msg, tmp.result); /【修改】將結(jié)構(gòu)體的部變量作為格式化參數(shù) 規(guī)則3.2:格式化輸出函數(shù)的格式化參數(shù)和實參個數(shù)必須匹配說明:使用格式化字符串應(yīng)該小心,確保格式字符和參數(shù)在數(shù)量上的匹配。格式字符和參數(shù)之間的不匹配會導(dǎo)致未定義的行為。大多數(shù)情況下,不正確的格式化字符串會導(dǎo)致程序異常終止。錯誤示例:格式字符和參數(shù)的數(shù)量不匹配,格式化字符串在編碼時會大量使用,如拼裝SQL語句和拼裝調(diào)試信息。尤其是調(diào)試信息,量大時容易copy-paste省事,這就容易出現(xiàn)不匹配的錯誤。void Noncompliant()char *error_msg = "Resource not ava
37、ilable to user."/* .do something. */printf("Error (type %s)n"); /【錯誤】格式化參數(shù)個數(shù)不匹配推薦做法:void Compliant()char *error_msg = "Resource not available to user."/* .do something. */printf("Error (type %s)n", error_msg); /【修改】使格式化參數(shù)個數(shù)匹配規(guī)則3.3:禁止以用戶輸入來構(gòu)造格式化字符串說明:調(diào)用格式化I/O函數(shù)時,不要直
38、接或者間接將用戶輸入作為格式化字符串的一部分或者全部。如果攻擊者對一個格式化字符串可以部分或完全控制,將導(dǎo)致進程崩潰、查看棧的容、改寫存、甚至執(zhí)行任意代碼等風(fēng)險。錯誤示例:下列代碼直接將用戶輸入作為格式字符串輸出。void Noncompliant(char *user, char *password) char input1000; if (fgets(input, sizeof(input) - 1, stdin) = NULL) /* handle error */ inputsizeof(input)-1 = 0; printf(input); /【錯誤】不允許將用戶輸入直接作為格式字
39、符串示例代碼的input直接來自用戶輸入,并作為格式化字符串直接傳遞給printf()。當(dāng)用戶輸入的是“%s%s%s%s%s%s%s%s%s%s%s%s”,就可能觸發(fā)無效指針或未映射的地址讀取。格式字符%s顯示棧上相應(yīng)參數(shù)所指定的地址的存。這里input被當(dāng)成格式化字符串,而沒有提供參數(shù),因此printf()讀取棧中任意存位置,直到格式字符耗盡或者遇到一個無效指針或未映射地址為止。推薦做法:通過顯式參數(shù)”%s”將 printf()的格式化字符串確定下來。void Compliant(char *user, char *password) char input1000; if (fgets(in
40、put, sizeof(input)-1, stdin) = NULL) /* handle error */ inputsizeof(input)-1 = 0; printf(“%s”, input); /【修改】通過%s將格式字符串確定下來建議3.1:使用格式化函數(shù)時推薦使用精度說明符說明:使用格式化函數(shù)時(例如sprintf(),scanf_s()等),可能會含有字符串參數(shù),應(yīng)盡量為格式化指示符加上精度說明符以限制拷貝字符串的長度,防止緩沖區(qū)溢出漏洞。錯誤示例:使用格式化函數(shù)sprintf,沒有添加精度說明符,可能會導(dǎo)致緩沖區(qū)溢出。#define BUF_SIZE 128void NoC
41、ompliant()char bufferBUF_SIZE + 1;sprintf( buffer, "Usage: %s argumentn", argv0 );/* .do something. */推薦做法:優(yōu)先采用snprintf替代sprintf來防止緩沖區(qū)溢出。若沒有帶n版本的snprintf函數(shù),可參考如下示例,使用sprintf,在接收字符串時,加上精度說明符,確定接收的長度,以免造成緩沖區(qū)溢出。#define BUF_SIZE 128void Compliant()char bufferBUF_SIZE + 1;sprintf(buffer, "
42、Usage: %.100s argumentn", argv0); /*【修改】字符串加上精度說明符 */* .do something. */通過精度限制從argv0 中只能拷貝 100 個字節(jié)。4 整數(shù)安全C99標(biāo)準定義了整型提升(integer promotions)、整型轉(zhuǎn)換級別(integer conversion rank)以及普通算術(shù)轉(zhuǎn)換(usual arithmetic conversions)的整型操作。不過這些操作實際上也帶來了安全風(fēng)險。規(guī)則4.1:確保無符號整數(shù)運算時不會出現(xiàn)反轉(zhuǎn)說明:反轉(zhuǎn)是指無法用無符號整數(shù)表示的運算結(jié)果將會根據(jù)該類型可以表示的最大值加1執(zhí)行求
43、模操作。將運算結(jié)果用于以下之一的用途,應(yīng)防止反轉(zhuǎn):l 作為數(shù)組索引l 指針運算l 作為對象的長度或者大小l 作為數(shù)組的邊界l 作為存分配函數(shù)的實參錯誤示例:下列代碼可能導(dǎo)致相加操作產(chǎn)生無符號數(shù)反轉(zhuǎn)現(xiàn)象。INT32 NoCompliant(UINT32 ui1, UINT32 ui2, UINT32 * ret)if( NULL = ret )return ERROR;*ret = ui1 + ui2;/*上面的代碼可能會導(dǎo)致ui1加ui2產(chǎn)生無符號數(shù)反轉(zhuǎn)現(xiàn)象,譬如ui1 = UINT_MAX且ui2 = 2;這可能會導(dǎo)致后面的存分配數(shù)量不足或者產(chǎn)生易被利用的潛在風(fēng)險;*/return (OK)
44、;推薦做法:INT32 Compliant(UINT32 ui1, UINT32 ui2, UINT32 * ret)if( NULL = ret )return ERROR;if(UINT_MAX - ui1) < ui2) /【修改】確保無符號整數(shù)運算時不會出現(xiàn)反轉(zhuǎn)return ERROR;else*ret = ui1+ ui2;return OK;延伸閱讀材料:漏洞VU#551436就是因為反轉(zhuǎn)問題,導(dǎo)致分配存空間不足,引發(fā)堆溢出。規(guī)則4.2:確保有符號整數(shù)運算時不會出現(xiàn)溢出說明:整數(shù)溢出是是一種未定義的行為,意味著編譯器在處理有符號整數(shù)溢出時具有很多選擇。將運算結(jié)果用于以下之一的
45、用途,應(yīng)防止溢出:l 作為數(shù)組索引l 指針運算l 作為對象的長度或者大小l 作為數(shù)組的邊界l 作為存分配函數(shù)的實參錯誤示例:下列代碼中兩個有符號整數(shù)相乘可能會產(chǎn)生溢出。INT32 NoCompliant(INT32 si1, INT32 si2, INT32 *ret)if ( NULL = ret )return ERROR;*ret = si1 * si2;/* 上面的代碼可能會產(chǎn)生兩個有符號整數(shù)相乘可能會產(chǎn)生溢出,譬如si1 = INT_MAX且si2 非0;*/return OK;推薦做法:INT32 Compliant(INT32 si1, INT32 si2, INT32 *ret
46、)if ( NULL = ret )return ERROR;INT64 tmp = (INT64)si1 *(INT64)si2; /*【修改】確保有符號整數(shù)運算時不會出現(xiàn)溢出 */if(INT_MAX < tmp) | (INT_MIN > tmp)return ERROR;*ret = si1 * si2;return OK;延伸閱讀材料:整數(shù)溢出可能導(dǎo)致緩沖區(qū)溢出以及任意代碼執(zhí)行。Apple Mac OS X 10.3及以前版本在處理GIF文件時,存在整數(shù)溢出漏洞,可被利用執(zhí)行任意代碼。攻擊者可以將特定的GIF文件放在Web頁面或者附件中,誘使目標(biāo)打開此文件從而觸發(fā)利用。具
47、體可參考US-CERT披露的漏洞VU#559444。規(guī)則4.3:確保整型轉(zhuǎn)換時不會出現(xiàn)截斷錯誤說明: 將一個較大整型轉(zhuǎn)換為較小整型,并且該數(shù)的原值超出較小類型的表示圍,就會發(fā)生截斷錯誤,原值的低位被保留而高位被丟棄。截斷錯誤會引起數(shù)據(jù)丟失,甚至可能引發(fā)安全問題。特別是將運算結(jié)果用于以下用途:l 作為數(shù)組索引l 指針運算l 作為對象的長度或者大小l 作為數(shù)組的邊界(如作為循環(huán)計數(shù)器)錯誤示例:數(shù)據(jù)類型強制轉(zhuǎn)化導(dǎo)致數(shù)據(jù)被截斷。INT32 NoCompliant(UINT32 ui, INT8 *ret)if( NULL = ret )return ERROR;*ret = (INT8)ui;/*上
48、面的代碼會導(dǎo)致數(shù)據(jù)被截斷,譬如ui = UINT_MAX場景下*/return (OK); 推薦做法:INT32 Compliant(UINT32 ui, INT8 *ret)if(NULL = ret)return ERROR;if(SCHAR_MAX >= ui) /【修改】確保整型轉(zhuǎn)換時不會出現(xiàn)截斷*ret = (INT8)ui;elsereturn ERROR; return OK; 規(guī)則4.4:確保整型轉(zhuǎn)換時不會出現(xiàn)符號錯誤說明: 有時從帶符號整型轉(zhuǎn)換到無符號整型會發(fā)生符號錯誤,符號錯誤并不丟失數(shù)據(jù),但數(shù)據(jù)失去了原來的含義。帶符號整型轉(zhuǎn)換到無符號整型,最高位(high-orde
49、r bit)會喪失其作為符號位的功能。如果該帶符號整數(shù)的值非負,那么轉(zhuǎn)換后值不變;如果該帶符號整數(shù)的值為負,那么轉(zhuǎn)換后的結(jié)果通常是一個非常大的正數(shù)。錯誤示例:符號錯誤繞過長度檢查#define BUF_SIZE 10int main(int argc, char* argv)intlength;char bufBUF_SIZE;if (argc != 3)return -1;length = atoi(argv1); /【錯誤】atoi返回值可能為負數(shù)if (length < BUF_SIZE) / len為負數(shù),長度檢查無效memcpy(buf, argv2, length); /*
50、帶符號的len被轉(zhuǎn)換為size_t類型的無符號整數(shù),負值被解釋為一個極大的正整數(shù)。memcpy()調(diào)用時引發(fā)buf緩沖區(qū)溢出*/printf("Data copiedn");elseprintf("Too many datan");推薦做法1:將length聲明為無符號整型,這樣符號錯誤后產(chǎn)生的極大正整數(shù)可以在與BUF_SIZE比較時檢查出來;推薦做法2:在長度檢查時,除了要保證長度小于BUF_SIZE,還要保證長度大于0。規(guī)則4.5:把整型表達式比較或賦值為一種更大類型之前必須用這種更大類型對它進行求值說明:若一個整型表達式與一個很大長度的整數(shù)類型進行
51、比較或者賦值為這種類型的變量,需要對該整型表達式的其中一個操作數(shù)類型顯示轉(zhuǎn)換為更大長度的整數(shù)類型,用這種更大的進行求值。這里所說的更大整數(shù)類型是相對整型表達式的操作數(shù)類型而言,譬如整型表達式的操作數(shù)類型是unsigned int ,則該規(guī)則所說的更大類型是指 unsigned long long。錯誤示例:數(shù)據(jù)類型不一致導(dǎo)致整型表達式賦值錯誤。void *NoCompliant(UINT32 blockNum)if(0 = blockNum )return NULL;UINT64 alloc = blockNum * 16;/*blockNum為32位的無符號數(shù),兩個32位的數(shù)相乘仍為32位的
52、數(shù),這會導(dǎo)致alloc <= UNIT_MAX始終為TRUE.*/return (alloc <= UINT_MAX)?malloc(blockNum*16):NULL;/*.申請的存使用后free.*/ 推薦做法:void *Compliant(UINT32 blockNum)if(0 = blockNum )return NULL;UINT64 alloc = (UINT64)blockNum * 16; /*【修改】確保整型表達式轉(zhuǎn)換時不出現(xiàn)數(shù)值錯誤 */return (alloc <= UINT_MAX)?malloc(blockNum*16):NULL;/*.申請的
53、存使用后free.*/ 建議4.1:避免對有符號整數(shù)進行位操作符運算說明:位操作符(、>>、<<、&、|)應(yīng)該只用于無符號整型操作數(shù),因為有符號整數(shù)上的有些位操作的結(jié)果是由編譯器所決定的,可能會出現(xiàn)出乎意料的行為或編譯器定義的行為。 錯誤示例:對有符號數(shù)作位操作運算。#define BUF_LEN (4)INT32 NoCompliant(void)INT32 ret = 0;INT32 i = 0x8000000; /【不推薦】避免使用有符號數(shù)作位操作符運算INT8 bufBUF_LEN;memset(buf,0,BUF_LEN);ret = snprintf(buf, BUF_LEN, "%u", i >> 24); /* i >>
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 三農(nóng)村合作社合作模式優(yōu)化方案
- 防撞護欄安裝施工方案
- 轉(zhuǎn)換層模板施工方案
- 不銹鋼雨棚施工方案
- 綦江酒店鋁單板施工方案
- 龍泉塑石假山制作施工方案
- 路面瀝青工程施工方案
- 臨床急性化膿性扁桃體炎和傳染性單核細胞增多癥鑒別診斷、相同點及區(qū)別
- 杭州扣盤式腳手架施工方案
- 桐梓科學(xué)開展松樹育苗和病蟲害防治工作的實踐及成果分析
- 閘調(diào)器介紹講解
- 唐僧團隊之如何打造團隊
- 畢業(yè)設(shè)計外文文獻-Spring Boot
- 六年級下冊《生命.生態(tài).安全》全冊教案(表格式)
- DB32/T 4444-2023 單位消防安全管理規(guī)范-高清版
- 《讓孩子成才的秘密》寂靜法師
- 水下作業(yè)工程監(jiān)理實施細則(工程通用版范本)
- 小學(xué)科學(xué)教育探究一研討教學(xué)法
- GB 14930.1-2022食品安全國家標(biāo)準洗滌劑
- YY/T 0972-2016有源植入醫(yī)療器械植入式心律調(diào)節(jié)設(shè)備用四極連接器系統(tǒng)尺寸和試驗要求
- 衛(wèi)生院處方點評記錄表
評論
0/150
提交評論