本書是業(yè)界最廣泛采納的編程指導(dǎo)原則匯編 ,它緊扣各個版本的C語言標準,分門別類地介紹了各種可能引發(fā)可利用安全漏洞的未定義行為、未指定行為,提出了安全編碼的規(guī)則和建議,在每條規(guī)則和建議上都用現(xiàn)實的相容及不相容代碼示例加以說明,本書是該標準文檔的第2版,加入了對最新的C11標準的支持,對于所有有志于C語言軟件開發(fā)的技術(shù)人員來說,都是不可或缺的參考書。
全書共14章,包括98條編碼規(guī)則,每條規(guī)則都由一個標題、一段說明和不相容/相容的代碼示例組成。第1章講述與預(yù)處理器相關(guān)的規(guī)則;第2章介紹的規(guī)則與聲明和初始化相關(guān);第3章介紹的是與表達式相關(guān)的規(guī)則;第4~7章講述的規(guī)則分別與整數(shù)、浮點數(shù)、數(shù)組及字符和字符串相關(guān);第8章介紹與內(nèi)存管理相關(guān)的規(guī)則;第9章講解的規(guī)則與輸入/輸出相關(guān);第10章介紹的規(guī)則與環(huán)境相關(guān);第11~13章分別講解與信號、錯誤處理和并發(fā)性有關(guān)的規(guī)則;第14章講述幾條雜項規(guī)則。最后提供3個附錄,分別包括本書使用的詞匯表、未定義行為和未指定行為。
C語言安全編程的難度可能超乎許多有經(jīng)驗的程序員的想象。為了幫助編程人員編寫更安全的代碼,本書提供了CERT C安全編碼標準第二個正式發(fā)行版本的完整文檔。這個新版本中的規(guī)則有助于確保程序員的代碼完全遵循新的C11標準;它也處理早期版本(包括C99)的問題。
新標準列舉了當(dāng)前C語言軟件漏洞的根源,按照嚴重性、利用的可能性和補救成本排定優(yōu)先級。書中的98個指導(dǎo)方針都包含了不安全代碼和對應(yīng)的C11相容安全實現(xiàn)。如果統(tǒng)一應(yīng)用,這些指導(dǎo)方針將消除導(dǎo)致緩沖區(qū)溢出、格式字符串漏洞、整數(shù)溢出和其他常見漏洞的嚴重編碼錯誤。
Preface 前 言本書為C語言編碼提供了規(guī)則。這些規(guī)則的目標是開發(fā)安全、可靠和穩(wěn)固的系統(tǒng),例如,消除可能導(dǎo)致程序意外行為和可利用漏洞的未定義行為。遵循本標準定義的編碼規(guī)則是確保C語言開發(fā)的軟件系統(tǒng)安全、可靠、穩(wěn)固的必要條件(但不是充分條件)。安全和穩(wěn)固的設(shè)計也是必要的,安全性關(guān)鍵系統(tǒng)通常會提出比編碼標準更嚴格的要求,例如,要求所有內(nèi)存都是靜態(tài)分配的。然而,應(yīng)用本編碼標準將產(chǎn)生高質(zhì)量的系統(tǒng),這些系統(tǒng)可靠、健壯并且能夠抵御攻擊。
每條規(guī)則都由一個標題、一段說明和不相容/相容的代碼示例組成。標題是規(guī)則的簡潔描述,但是有時候不夠精確。說明提出了規(guī)則的規(guī)范要求。不相容代碼示例是違反規(guī)則的代碼示例。搭配的相容解決方案展示了等價的代碼,這些代碼不違反該規(guī)則或者該編碼標準中的任何其他規(guī)則。
具有良好文檔、可以實施的編碼標準是C語言編碼必不可少的要素。編碼標準鼓勵程序員遵循由項目需求和組織確定的一組統(tǒng)一規(guī)則,而不是簡單地采用程序員熟悉的方法。一旦確定,這些標準可以作為評估源代碼(使用人工或者自動化過程)的指標。
CERT編碼規(guī)則為業(yè)界廣泛采納。Cisco系統(tǒng)公司在2011年10月的Cisco年度SecCon會議上宣布在其產(chǎn)品開發(fā)中采用CERT C安全編碼標準作為基準編程標準。最近,Oracle將所有CERT安全編碼標準整合到現(xiàn)有的安全編碼標準中。注意,這是長期協(xié)作中的最新步驟:CERT和Oracle以前合作編寫了《The CERT Oracle Secure Coding Standard for Java》(Addison-Wesley,2011)。
Robert C. Seacord 是卡內(nèi)基-梅隆大學(xué)軟件工程研究所(SEI)CERT計劃的安全編碼技術(shù)經(jīng)理。CERT項目是運營相關(guān)網(wǎng)絡(luò)安全研究和對美國網(wǎng)絡(luò)安全挑戰(zhàn)創(chuàng)新/及時響應(yīng)的可信提供商。安全編碼倡議和軟件開發(fā)人員及軟件開發(fā)組織合作,在部署之前消除由于編碼錯誤造成的安全漏洞。Robert還是卡內(nèi)-基梅隆大學(xué)計算機科學(xué)學(xué)院和信息網(wǎng)絡(luò)學(xué)院的副教授。他曾經(jīng)撰寫過8本書籍,包括《Secure Coding in C and C++》第2版和《Java Coding Guidelines: 75 Recommendations for Reliable and Secure Programs》等。他還發(fā)表過40篇軟件安全性、基于組件的軟件工程、基于Web系統(tǒng)設(shè)計、遺留系統(tǒng)現(xiàn)代化、組件儲存庫和搜索引擎以及用戶界面設(shè)計和開發(fā)方面的論文。
譯者序
前言
貢獻者簡介
第1章 預(yù)處理器(PRE)
1.1 PRE30-C. 不要通過連接創(chuàng)建通用字符名稱
1.2 PRE31-C. 避免不安全宏參數(shù)的副作用
1.3 PRE32-C. 不要在類函數(shù)的宏調(diào)用中使用預(yù)處理器指令
第2章 聲明和初始化(DCL)
2.1 DCL30-C. 聲明具有正確存儲持續(xù)期的對象
2.2 DCL31-C. 在使用前聲明標識符
2.3 DCL36-C. 不要聲明具有沖突鏈接類別的標識符
2.4 DCL37-C. 不要聲明或者定義保留標識符
2.5 DCL38-C. 使用正確語法聲明靈活數(shù)組成員
2.6 DCL39-C. 避免在結(jié)構(gòu)填充中泄露信息
2.7 DCL40-C. 不要創(chuàng)建相同函數(shù)或者對象的不兼容聲明
2.8 DCL41-C. 不要在switch語句第一個條件標簽之前聲明變量
第3章 表達式(EXP)
3.1 EXP30-C. 不要依賴求值順序以避免副作用
3.2 EXP32-C. 不要通過非易失性引用訪問易失性對象
3.3 EXP33-C. 不要讀取未初始化的內(nèi)存
3.4 EXP34-C. 不要對null指針進行解引用
3.5 EXP35-C. 不要修改具有臨時生命期的對象
3.6 EXP36-C. 不要將指針轉(zhuǎn)換為更嚴格對齊的指針類型
3.7 EXP37-C. 用正確數(shù)量和類型的參數(shù)調(diào)用函數(shù)
3.8 EXP39-C. 不要通過不兼容類型的指針訪問變量
3.9 EXP40-C. 不要修改常量對象
3.10 EXP42-C. 不要比較填充數(shù)據(jù)
3.11 EXP43-C. 使用restrict限定的指針時避免未定義行為
3.12 EXP44-C. 不要向sizeof、_Alignof或者_Generic傳遞有副作用的操作數(shù)
3.13 EXP45-C. 不要在選擇語句中執(zhí)行賦值
第4章 整數(shù)(INT)
4.1 INT30-C. 確保無符號整數(shù)運算不產(chǎn)生回繞
4.2 INT31-C. 確保整數(shù)轉(zhuǎn)換不會造成數(shù)據(jù)丟失或者錯誤解釋
4.3 INT32-C. 確保有符號整數(shù)的運算不造成溢出
4.4 INT33-C. 確保除法和余數(shù)運算不會造成0除數(shù)錯誤
4.5 INT34-C. 不要用負數(shù)或者不小于操作數(shù)位數(shù)的位數(shù)對表達式進行移位
4.6 INT35-C. 使用正確的整數(shù)精度
4.7 INT36-C. 將指針轉(zhuǎn)換為整數(shù)或者將整數(shù)轉(zhuǎn)換為指針
第5章 浮點數(shù)(FLP)
5.1 FLP30-C. 不要使用浮點變量作為循環(huán)計數(shù)器
5.2 FLP32-C. 避免或者檢測數(shù)學(xué)函數(shù)中的定義域和值域錯誤
5.3 FLP34-C. 確保浮點數(shù)轉(zhuǎn)換在新類型的范圍內(nèi)
5.4 FLP36-C. 將整數(shù)值轉(zhuǎn)換為浮點指針類型時保持精度
第6章 數(shù)組(ARR)
6.1 ARR30-C. 不要形成或者使用超限的指針或者數(shù)組下標
6.2 ARR32-C. 確保變長數(shù)組的大小參數(shù)在有效范圍內(nèi)
6.3 ARR36-C. 不要進行兩個不引用相同數(shù)組的指針之間的減法或者比較
6.4 ARR37-C. 不要在指向非數(shù)組對象的指針上加或者減一個整數(shù)
6.5 ARR38-C. 保證庫函數(shù)不形成無效指針
6.6 ARR39-C. 不要在指針上加或者減一個按比例調(diào)整的整數(shù)
第7章 字符和字符串(STR)
7.1 STR30-C. 不要企圖修改字符串字面量
7.2 STR31-C. 保證字符串存儲有足夠的空間容納字符數(shù)據(jù)和null結(jié)束符
7.3 STR32-C. 不要向要求字符串參數(shù)的庫函數(shù)傳遞非null結(jié)束字符序列
7.4 STR34-C. 在轉(zhuǎn)換為更大的整數(shù)尺寸之前將字符轉(zhuǎn)換為unsigned char類型
7.5 STR37-C. 字符串處理函數(shù)的實參必須可以表示為unsigned char
7.6 STR38-C. 不要混淆窄和寬字符串及函數(shù)
第8章 內(nèi)存管理(MEM)
8.1 MEM30-C. 不要訪問已釋放內(nèi)存
8.2 MEM31-C. 在不再需要時釋放動態(tài)分配的內(nèi)存
8.3 MEM33-C. 動態(tài)分配和復(fù)制包含靈活數(shù)組成員的結(jié)構(gòu)
8.4 MEM34-C. 只釋放動態(tài)分配的內(nèi)存
8.5 MEM35-C. 為對象分配足夠的內(nèi)存
8.6 MEM36-C. 不要通過調(diào)用realloc()修改對象的對齊方式
第9章 輸入/輸出(FIO)
9.1 FIO30-C. 從格式字符串中排除用戶輸入
9.2 FIO31-C. 不要打開已經(jīng)打開的文件
9.3 FIO32-C. 不要在只適合文件的設(shè)備上執(zhí)行操作
9.4 FIO34-C. 區(qū)分從文件讀入的字符和EOF/WEOF
9.5 FIO37-C. 不要假定fgets()或者fgetws()在成功時返回非空字符串
9.6 FIO38-C. 不要復(fù)制FILE對象
9.7 FIO39-C. 不要在沒有中間刷新或者定位調(diào)用的情況下在一個流中交替輸入和輸出
9.8 FIO40-C. 在fgets()或者fgetws()失敗時重置字符串
9.9 FIO41-C. 不要用有副作用的流作為實參調(diào)用getc()、putc()、getwc()或者putwc()
9.10 FIO42-C. 在不再需要時關(guān)閉文件
9.11 FIO44-C. 對fsetpos()只使用fgetpos()返回的值
9.12 FIO45-C. 避免訪問文件時出現(xiàn)TOCTOU競爭條件
9.13 FIO46-C. 不要訪問已關(guān)閉文件
9.14 FIO47-C. 使用有效格式字符串