溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何實(shí)現(xiàn)防御式編程

發(fā)布時(shí)間:2020-06-06 09:26:43 來(lái)源:億速云 閱讀:229 作者:Leah 欄目:網(wǎng)絡(luò)安全

如何實(shí)現(xiàn)防御式編程?針對(duì)這個(gè)問題,今天小編總結(jié)這篇有關(guān)防御式編程的文章,希望能幫助更多想解決這個(gè)問題的朋友找到更加簡(jiǎn)單易行的辦法。

防御式編程的全部重點(diǎn)就在于防御那些你未曾預(yù)料到的錯(cuò)誤。
防御式編程的主要思想:子程序應(yīng)該不因傳入錯(cuò)誤數(shù)據(jù)而被破壞,哪怕是由其他子程序產(chǎn)生錯(cuò)誤數(shù)據(jù)。更一般地說(shuō),其核心想法是要承認(rèn)程序都會(huì)有問題,都需要被修改,聰明的程序員應(yīng)該根據(jù)這一點(diǎn)來(lái)編程序。

一、保護(hù)程序免遭非法輸入數(shù)據(jù)的破壞
對(duì)已形成產(chǎn)品的軟件而言:不管進(jìn)來(lái)的數(shù)據(jù)如何,都不應(yīng)該產(chǎn)程垃圾數(shù)據(jù)。(必要的錯(cuò)誤提示)
通常有三種方法來(lái)處理進(jìn)來(lái)的垃圾數(shù)據(jù):
1、檢查所有來(lái)源于外部的數(shù)據(jù)的值
當(dāng)從文件、用戶、網(wǎng)絡(luò)或其他外部接口中獲取數(shù)據(jù)時(shí),應(yīng)檢查所獲得的數(shù)據(jù)值,以確保它在允許的范圍內(nèi)。
2、檢查子程序所有輸入?yún)?shù)的值
數(shù)據(jù)來(lái)源于其他子程序,而不是外部接口。
3、決定如何處理錯(cuò)誤的輸入數(shù)據(jù)
一旦檢測(cè)到非法數(shù)據(jù),就應(yīng)該處理它。
注:防范看似微小的錯(cuò)誤,收獲可能遠(yuǎn)遠(yuǎn)超出你的想象。

二、斷言(Assertions)
斷言定義:指在開發(fā)期間使用的,讓程序在運(yùn)行時(shí)進(jìn)行自檢的代碼(通??梢允亲映绦蚧蚝辏#▽?duì)大型的復(fù)雜程序或可靠性要求極高的程序來(lái)說(shuō)尤其重要)
Java斷言:兩個(gè)參數(shù)—>assert(“bool表達(dá)式”,“當(dāng)判斷條件為false時(shí)的錯(cuò)誤信息”)

斷言檢查如下這類假定:
1、  輸入?yún)?shù)和輸出參數(shù)的取值處于預(yù)期的范圍內(nèi)。
2、  子程序開始(或結(jié)束)執(zhí)行時(shí),文件或流是處于打開(或關(guān)閉)的狀態(tài)。
3、  子程序開始(或結(jié)束)執(zhí)行時(shí),文件或流的讀寫位置處于開頭(或結(jié)尾)處。
4、  文件或流已用只讀、只寫或可讀可寫方式打開。
5、  僅用于輸入的變量的值,沒有被子程序所修改。
6、  指針非空。
7、  傳入子程序的數(shù)組或其他容器至少能容納X個(gè)數(shù)據(jù)元素。
8、  表已經(jīng)初始化,存儲(chǔ)著真實(shí)的數(shù)據(jù)。
9、  子程序開始(或結(jié)束)執(zhí)行時(shí),某個(gè)容器是空的(滿的)。
注:斷言主要是用于開發(fā)和維護(hù)階段,而在生成產(chǎn)品代碼時(shí)并不編譯到目標(biāo)代碼中,以免降低系統(tǒng)性能。

1、建立自己的斷言機(jī)制
※ C++、Java、VB在內(nèi)的很多語(yǔ)言都支持?jǐn)嘌浴?br/>※ C++中標(biāo)準(zhǔn)的assert宏并不支持文本信息。

2、使用斷言的指導(dǎo)建議
斷言的指導(dǎo)建議:

用錯(cuò)誤處理代碼來(lái)處理預(yù)期會(huì)發(fā)生的狀況,用斷言來(lái)處理決不應(yīng)該發(fā)生的狀況。
異常發(fā)生,觸發(fā)斷言的情況下,就應(yīng)該修改程序的源代碼并重新編譯。

避免把需要執(zhí)行的代碼放到斷言中
※ 一種危險(xiǎn)的斷言使用方法(如果斷言關(guān)閉,代碼不能被編譯):
Debug.Assert( PerformAction() )
※ 安全地使用斷言
actionPerformed = PerformAction()
Debug.Assert( actionPerformed )

用斷言來(lái)注解并驗(yàn)證前條件和后條件
※ 如果數(shù)據(jù)來(lái)源于系統(tǒng)外部,那么就應(yīng)該用錯(cuò)誤處理代碼來(lái)檢查和處理非法的數(shù)值。
※ 如果變量的值來(lái)源于可信的系統(tǒng)內(nèi)部,那么使用斷言是很合適的。

對(duì)于高健壯性的代碼,應(yīng)該先使用斷言再處理錯(cuò)誤
※ Microsoft Word,在其代碼中,對(duì)應(yīng)該始終為真的條件都加上了斷言,但同時(shí)也用錯(cuò)誤處理代碼處理了這些錯(cuò)誤,以應(yīng)對(duì)斷言失敗的情況。

三、錯(cuò)誤處理技術(shù)
如何處理那些預(yù)料中的程序錯(cuò)誤:
※ 返回中立值、換用下一個(gè)正確數(shù)據(jù)、返回與前次相同的值、換用最接近的有效值、在日志文件中記錄警告信息、返回一個(gè)錯(cuò)誤碼、調(diào)用錯(cuò)誤處理子程序或?qū)ο?、顯示出錯(cuò)信息或關(guān)閉程序。

1、返回中立值
※ 有時(shí),處理錯(cuò)誤的最佳做法就是繼續(xù)執(zhí)行操作并簡(jiǎn)單地返回一個(gè)沒有危害的數(shù)值。
※ 例如:數(shù)值操作可以返回0、字符串操作可以返回空字符串、指針操作可以返回空指針。

2、換用下一個(gè)正確的數(shù)據(jù)
※ 例如:數(shù)據(jù)庫(kù)記錄讀取、文件行信息讀取等。

3、返回與前次相同的數(shù)據(jù)

4、換用最接近的合法值
※ 例如:汽車的速度表無(wú)法顯示負(fù)的速度,所以在倒車時(shí),它簡(jiǎn)單的顯示為0。

5、把警告信息記錄到日志文件中
※ 要考慮是否能夠安全地公開它,或者是否需要對(duì)其進(jìn)行加密或?qū)嵤┢渌绞降谋Wo(hù)。

6、返回一個(gè)錯(cuò)誤碼
※ 可以決定在讓系統(tǒng)得某些部分處理錯(cuò)誤,其他部分則不在本地(局部)處理錯(cuò)誤,而只是簡(jiǎn)單地報(bào)告說(shuō)有錯(cuò)誤發(fā)生。
采用方法:
※ 設(shè)置一個(gè)狀態(tài)變量的值
※ 用狀態(tài)值作為函數(shù)的返回值
※ 用語(yǔ)言內(nèi)建的異常機(jī)制拋出一個(gè)異常
注:如果安全性很重要,請(qǐng)確認(rèn)調(diào)用方的子程序總會(huì)檢查返回的錯(cuò)誤嗎。

7、調(diào)用錯(cuò)誤處理子程序或?qū)ο?br/>※ 可以把錯(cuò)誤處理都集中在一個(gè)全局的錯(cuò)誤處理子程序或?qū)ο笾羞M(jìn)行。
※ 優(yōu)點(diǎn):能把錯(cuò)誤處理的職責(zé)集中在一起,從而讓調(diào)試更為簡(jiǎn)單。
缺點(diǎn):整個(gè)程序都要知道這個(gè)集中點(diǎn),并與之緊密耦合。

8、當(dāng)錯(cuò)誤發(fā)生時(shí)顯示出錯(cuò)消息
※ 可以把錯(cuò)誤處理的開銷降低。

9、用最妥當(dāng)?shù)姆绞皆诰植刻幚礤e(cuò)誤
※ 給程序員帶來(lái)靈活度的同時(shí),也帶來(lái)了顯著的風(fēng)險(xiǎn)。即:系統(tǒng)的整體性能將無(wú)法滿足對(duì)其正確性或可靠性的需求。

10、關(guān)閉程序
※ 適用于人身安全攸關(guān)的應(yīng)用程序。

健壯性與正確性
※ 處理錯(cuò)誤最恰當(dāng)?shù)姆绞揭鶕?jù)出現(xiàn)錯(cuò)誤的軟件的類別而定。錯(cuò)誤處理有時(shí)更側(cè)重于正確性,有時(shí)更側(cè)重于健壯性。
※ 正確性:意味著永不返回不準(zhǔn)確的結(jié)果,哪怕不返回結(jié)果也比返回不準(zhǔn)確的結(jié)果要好。
※ 健壯性:意味著要不斷嘗試采取某些措施,以保證軟件可以持續(xù)地運(yùn)轉(zhuǎn)下去,哪怕有時(shí)做出一些不夠準(zhǔn)確的結(jié)果。

高層次設(shè)計(jì)對(duì)錯(cuò)誤處理方式的影響
※ 在整個(gè)程序里采用一致統(tǒng)一的方式來(lái)處理非法的參數(shù)。
※ 確定一種通用的處理錯(cuò)誤參數(shù)的方法,是架構(gòu)層次(高層次)的設(shè)計(jì)決策。
※ 一旦確定了某種方法,就要確保始終如一地貫徹這一方法。
※ 請(qǐng)?jiān)诿總€(gè)系統(tǒng)調(diào)用后檢查錯(cuò)誤碼。

四、異常
處理異常建議:
1、用異常通知程序的其他部分,發(fā)生了不可忽略的錯(cuò)誤
※ 異常機(jī)制的優(yōu)越之處就在于它能提供一種無(wú)法被忽略的錯(cuò)誤通知機(jī)制。
2、只在真正例外的情況下才拋出異常
※ 僅在其他編碼實(shí)踐方法無(wú)法解決的情況下才使用異常。
※ 異常同斷言相似:都是用來(lái)處理那些不僅罕見甚至永遠(yuǎn)不該發(fā)生的情況。
※ 異常的取舍:
1、異常是一種強(qiáng)大的用來(lái)處理預(yù)料之外的情況途徑。
2、程序的復(fù)雜度因此增加、性能也可能降低。
3、不能用異常來(lái)推卸責(zé)任
※ 能在局部處理的錯(cuò)誤,就應(yīng)該在局部處理,不能當(dāng)成異常拋出。
4、避免在構(gòu)造函數(shù)和析構(gòu)函數(shù)中拋出異常,除非你在同一地方把他們捕獲
※ 如果在構(gòu)造函數(shù)中拋出異常,就不會(huì)調(diào)用析構(gòu)函數(shù),從而造成潛在的資源泄漏。
5、在恰當(dāng)?shù)某橄髮哟螔伋霎惓?br/>※ 當(dāng)你決定把一個(gè)異常傳給調(diào)用方時(shí),請(qǐng)確保異常的抽象層次與子程序接口的抽象層次相一致。  
6、在異常消息中加入關(guān)于導(dǎo)致異常發(fā)生的全部信息
※ 要確保異常信息中含有為理解異常拋出原因所需要的全部信息。
7、避免使用空的catch語(yǔ)句
※ 注釋或日志記錄信息對(duì)這一情況文檔化。
8、了解所有函數(shù)庫(kù)可能跑出的異常
※ 一定要了解所用的函數(shù)庫(kù)都會(huì)拋出哪些異常。
※ 未能捕獲由函數(shù)庫(kù)拋出的異常將會(huì)導(dǎo)致程序崩潰。
9、考慮創(chuàng)建一個(gè)集中的異常報(bào)告機(jī)制
※ 能為一些與異常有關(guān)的信息提供一個(gè)集中的存儲(chǔ),如發(fā)生的異常種類、每個(gè)異常該如何被處理以及如何格式化異常信息。

10、把項(xiàng)目中對(duì)異常的使用標(biāo)準(zhǔn)化
※ 如果使用象C++一樣的語(yǔ)言,就應(yīng)該規(guī)定到底可以拋出哪些種類的異常。(考慮只拋出std::exception基類派生出的對(duì)象)
※ 考慮創(chuàng)建項(xiàng)目特定的異常類(用作項(xiàng)目可能異常的基類,這樣就能把紀(jì)錄日志、報(bào)告錯(cuò)誤等操作集中起來(lái)并標(biāo)準(zhǔn)化)。
※ 規(guī)定在何種場(chǎng)合允許代碼使用try-catch語(yǔ)句在局部對(duì)錯(cuò)誤進(jìn)行處理。
※ 規(guī)定在何種場(chǎng)合允許代碼拋出不在局部進(jìn)行處理的異常。
※ 確定是否要使用集中的異常報(bào)告機(jī)制。
※ 規(guī)定是否允許在構(gòu)造函數(shù)和析構(gòu)函數(shù)中使用異常。

11、考慮異常的替換方案
※ 請(qǐng)考慮你的系統(tǒng)是否真的需要異常。

五、隔離程序,使之包容由錯(cuò)誤造成的損害
隔欄(barricade)是一種容損策略。

1、在類的層次采用這樣的方法:
※ 類的public方法可以假定數(shù)據(jù)是不安全的,它們要負(fù)責(zé)檢查數(shù)據(jù)并進(jìn)行清理,一旦類的公用方法接受了數(shù)據(jù),那么類的私有方法就可以假定數(shù)據(jù)都是安全的了。

2、隔欄與斷言的關(guān)系:
※ 隔欄的使用使斷言和錯(cuò)誤處理有了清晰的區(qū)別。
※ 隔欄外部的程序應(yīng)該適用錯(cuò)誤處理技術(shù),而隔欄內(nèi)部的程序就應(yīng)該使用斷言技術(shù)。

六、輔助調(diào)試的代碼
防御式編程的另一個(gè)重要方面就是,適用調(diào)試助手(輔助調(diào)試代碼)。
1、不要自動(dòng)地把產(chǎn)品版的限制強(qiáng)加于開發(fā)版之上
※ 程序員常常有這樣一個(gè)誤區(qū):即認(rèn)為產(chǎn)品級(jí)軟件的種種限制也應(yīng)該在開發(fā)版本中得到體現(xiàn)(速度、對(duì)資源的限制)。
※ 應(yīng)該在開發(fā)階段犧牲一些速度和資源使用,來(lái)?yè)Q取一些可以讓開發(fā)順暢的內(nèi)置工具(輔助代碼)。

2、盡早引入輔助調(diào)試代碼
※ 越早引入輔助調(diào)試的代碼,它能提供的幫助也就越大。

3、采用進(jìn)攻式編程
※ 應(yīng)該以這么一種方式來(lái)處理異常:在開發(fā)階段讓它顯現(xiàn)出來(lái),而在產(chǎn)品代碼運(yùn)行時(shí)讓它能夠自我恢復(fù)。--- “進(jìn)攻式編程”
進(jìn)行進(jìn)攻式編程的方法:

確保斷言語(yǔ)句是程序終止運(yùn)行。
完全填充分配到的所有內(nèi)存,這樣可以讓你檢測(cè)到內(nèi)存分配錯(cuò)誤。

4、計(jì)劃移除調(diào)試輔助的代碼
※ 要事先做好計(jì)劃,避免調(diào)試代碼和程序代碼糾纏不清。

采取的方法:
※ 使用類似ant和make這樣的版本控制工具和make工具
  (可以從同一套源碼編譯出不同版本的程序)
※ 使用內(nèi)置的預(yù)處理器
※ 編寫你自己的預(yù)處理器
※ 使用調(diào)試存根(stubs)
  (兩套方案—開發(fā)版本和發(fā)布版本代碼)

七、確定在產(chǎn)品代碼中該保留多少防御式代碼
八、對(duì)防御式編程采取防御的姿態(tài)

看完這篇文章,你們學(xué)會(huì)使用防御式編程了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI