安全開(kāi)發(fā)規(guī)范(六)——面向?qū)ο?/h1>

一初婆、開(kāi)發(fā)安全風(fēng)險(xiǎn)評(píng)估

開(kāi)發(fā)安全規(guī)范 嚴(yán)重性 整改代價(jià) 優(yōu)先級(jí) 級(jí)別
1 在返回引用之前屁置,防御性復(fù)制私有的可變的類成員 12 1
2 小心處理構(gòu)造函數(shù)拋出異常的情況 12 1
3 聲明數(shù)據(jù)成員為私有并提供可訪問(wèn)的封裝器方法 12 1
4 比較類而不是進(jìn)行類名稱 9 2
5 不允許敏感類復(fù)制其自身 8 2
6 不要在嵌套類中暴露外部類的私有字段 8 2
7 不要使用公有靜態(tài)的非final變量 8 2
  • 級(jí)別:L1高危害划址、可利用性強(qiáng)该默、整改代價(jià)低般贼;
  • L2中危害瘸恼、可能被利用、整改代價(jià)中似谁;
  • 優(yōu)先級(jí):數(shù)值越高傲绣,越優(yōu)先修復(fù);
  • 來(lái)源:Java安全編碼標(biāo)準(zhǔn)/朗(Long巩踏, F.)等著秃诵,第六章

二、開(kāi)發(fā)安全規(guī)范說(shuō)明

1塞琼、在返回引用之前菠净,防御性復(fù)制私有的可變的類成員

返回類的內(nèi)部可變成員的引用,會(huì)破壞一個(gè)應(yīng)用的安全性,這個(gè)破壞既體現(xiàn)在對(duì)封裝性的破壞嗤练,也體現(xiàn)在為破壞類的內(nèi)部狀態(tài)提供了可能性。因此程序禁止返回內(nèi)部可變類成員的引用在讶。

返回一個(gè)指向可變內(nèi)部狀態(tài)的防御性復(fù)制的引用煞抬,能保證調(diào)用者不會(huì)修改初始的內(nèi)部狀態(tài),盡管這個(gè)副本仍然是可變的构哺。

  • 【情況1】返回私有對(duì)象引用或包含不可變對(duì)象的可變成員革答,使用clone()返回對(duì)象的克隆副本。
Public class Test_1_1 {
  Private Date date; // 對(duì)象引用
  Private HashMap<Integer曙强,String> hm = new HashMap<Integer残拐,String>(); // 包含不可變對(duì)象的可變成員
  Public Date getDate(){
    return (Date)date.clone();
  }
  Public String getString(int i){
    Return hm.get(i); // 直接return hm是不安全的。
  }
  Public HashMap<Integer碟嘴,String> getMap() {
    return (HashMap<Integer溪食,String>) hm.clone();
  }
}

注意:若類會(huì)被非受信代碼擴(kuò)展時(shí),在執(zhí)行一個(gè)構(gòu)造方法的防御性復(fù)制時(shí)娜扇,必須避免使用clone()方法错沃,改用原始的“創(chuàng)建對(duì)象,逐一賦值”的方法雀瓢,防止執(zhí)行被惡意覆寫了的clone()方法枢析。

  • 【情況2】返回私有可變對(duì)象數(shù)組,因?yàn)閿?shù)組中包含的對(duì)象引用是可變的刃麸,對(duì)數(shù)組進(jìn)行淺復(fù)制是不夠的醒叁,需采用深度復(fù)制。
Public class Test_1_2 {
  Private Date[] dates;
  Public Date[] getDates(){
    Date[] newDates = new Date[dates.length];
    For(int i = 0; i < dates.length; i++){
      newDates[i] = dates[i].clone();
    }
    Return newDates;
  }
}

2泊业、小心處理構(gòu)造函數(shù)拋出異常的情況

在一個(gè)構(gòu)造方法開(kāi)始創(chuàng)建對(duì)象把沼,但并未結(jié)束時(shí),對(duì)象只會(huì)被部分地初始化吁伺。

其他類可能會(huì)從并發(fā)運(yùn)行的線程中訪問(wèn)一個(gè)部分初始化的對(duì)象智政,在沒(méi)有原子性失效的時(shí)候,部分初始化會(huì)導(dǎo)致對(duì)象處于不一致的狀態(tài)箱蝠。

處理部分初始化對(duì)象的問(wèn)題有3種通用的解決方法:

  1. 在對(duì)象的構(gòu)造方法中拋出異常续捂。遺憾的是,攻擊者會(huì)惡意地獲得這樣一個(gè)對(duì)象的實(shí)例宦搬。例如牙瓢,一個(gè)使用終止器構(gòu)造方法的攻擊允許攻擊者調(diào)用類中的任意方法,即使這個(gè)類方法是由安全管理器保護(hù)的间校。

  2. 聲明對(duì)象的被初始化變量為final可以防止對(duì)象被部分初始化矾克。當(dāng)一個(gè)線程中執(zhí)行的構(gòu)造方法將一個(gè)final數(shù)據(jù)成員初始化成一個(gè)已知的安全值時(shí),另外的線程不能看到這個(gè)對(duì)象任何初始化之前的值憔足。

  3. 初始化標(biāo)志胁附。這個(gè)方法允許未初始化或者部分初始化的對(duì)象在已知的失效狀態(tài)下存在酒繁,這樣的對(duì)象就是我們通常認(rèn)為的僵尸對(duì)象(zombie object)。這個(gè)方案容易出錯(cuò)控妻,因?yàn)槿魏螌?duì)這樣一個(gè)類的訪問(wèn)必須要先檢查對(duì)象是否被正確地初始化州袒。

方案 未初始化值 部分初始化值
構(gòu)造函數(shù)中的異常 阻止 不阻止
Final數(shù)據(jù)成員(推薦) 阻止 阻止
初始化標(biāo)志 檢測(cè) 檢測(cè)

3、聲明數(shù)據(jù)成員為私有并提供可訪問(wèn)的封裝器方法

控制聲明為public或者protected的數(shù)據(jù)成員的訪問(wèn)方式是很困難的弓候,攻擊者會(huì)用意想不到的方式控制這些成員郎哭。

因此,數(shù)據(jù)成員必須聲明為private菇存,并使用public或者protected的封裝器方法提供數(shù)據(jù)訪問(wèn)夸研,監(jiān)視并控制對(duì)數(shù)據(jù)成員的修改,保持類的不變性依鸥。

當(dāng)數(shù)據(jù)成員是私有可變對(duì)象的引用時(shí)亥至,要特別注意不要直接返回引用,詳見(jiàn)規(guī)則1贱迟。

【例外】當(dāng)類僅作為數(shù)據(jù)結(jié)構(gòu)抬闯,而沒(méi)有任何行為時(shí),可以聲明數(shù)據(jù)成員為public关筒。

4溶握、比較類而不是進(jìn)行類名稱

在JVM中, “如果它們被同一個(gè)類裝載器裝載蒸播,并且有相同的全名睡榆,那么這兩個(gè)類被認(rèn)為是相同的類(并且因此有相同的類型)”。

但是袍榆,有同樣名稱卻來(lái)自不同包名的兩個(gè)類是不同的類胀屿,因此不能基于類名稱進(jìn)行比較。

  • 不符合規(guī)則的案例1:
// 基于類名稱進(jìn)行比較是不準(zhǔn)確的
a.getClass().getName().equals(b.getClass().getName())
  • 不符合規(guī)則的案例2:
// 比較類的全限定名也是不夠的包雀,
// 因?yàn)椴煌念愌b載器會(huì)裝載具有相同全限定名的不同的類到一個(gè)JVM中宿崭。
a.getClass().getName().equals(“com.test.a”) 
  • 符合規(guī)則的案例1:
a.getClass() == this.getClass().getClassLoader().loadClass(“com.test.a”);
  • 符合規(guī)則的案例2:
a.getClass() == b.getClass()

5、不允許敏感類復(fù)制其自身

最好不要復(fù)制包含私有才写、保密或者其他敏感數(shù)據(jù)的類葡兑。

如果一個(gè)類是不準(zhǔn)備被復(fù)制的,但它又沒(méi)有定義復(fù)制機(jī)制赞草,只通過(guò)構(gòu)造函數(shù)進(jìn)行安全檢查讹堤,是不足以防止復(fù)制的。

Java的對(duì)象克隆機(jī)制clone()允許攻擊者通過(guò)復(fù)制已有對(duì)象的內(nèi)存鏡像來(lái)創(chuàng)建一個(gè)類的新實(shí)例厨疙,而不是通過(guò)執(zhí)行這個(gè)類的構(gòu)造方法來(lái)創(chuàng)建新實(shí)例洲守。

利用該機(jī)制,通過(guò)創(chuàng)建子類(構(gòu)造方法中繞過(guò)父類的安全檢測(cè))和克隆子類實(shí)現(xiàn)敏感類的復(fù)制。

  • 符合規(guī)則的方案1:
    最容易防止利用惡意子類克隆的方法是聲明類為final梗醇。

  • 符合規(guī)則的方案2:
    定義一個(gè)總是拋出CloneNotSupportedException錯(cuò)誤的final clone方法知允,防止子類成為可克隆的。

6叙谨、不要在嵌套類中暴露外部類的私有字段

嵌套類指那些聲明在另一個(gè)類或者接口代碼塊中的類温鸽,嵌套類可以訪問(wèn)外被類的私有變量。

當(dāng)嵌套類被聲明為public或者當(dāng)它包含public的方法或者構(gòu)造方法時(shí)唉俗,可以被任何在同一個(gè)包里的其他類訪問(wèn)嗤朴。

因此配椭,嵌套類禁止將外部類的私有成員暴露給外部的類或者包虫溜。

  • 不符合規(guī)則的案例:
class Test_7_1 {
  Private int secret;
  Public class InnerClass { // 嵌套類
    Public int get(){ return secret; }
  }
}

Class Test_7_2 {
  Public static void main(String[] args) {
    Test_7_1 t = new Test_7_1();
    Test_7_1.InnerClass c = t. new InnerClass();
    c.get(); // 這里獲得Test_7_1的私有變量secret
  }
}
  • 符合規(guī)則的案例:
    InnerClass聲明為private來(lái)隱藏嵌套類,或?qū)⒖赡鼙┞端接谐蓡T的方法聲明為private股缸。

7衡楞、不要使用公有靜態(tài)的非final變量

客戶代碼可以輕易地訪問(wèn)到公有靜態(tài)數(shù)據(jù)成員。

安全管理器不會(huì)對(duì)讀取或?qū)懭脒@些變量進(jìn)行檢查敦姻。此外瘾境,在將新值存儲(chǔ)到這些字段之前,是不能通過(guò)編程方式進(jìn)行驗(yàn)證的镰惦。

在多線程的場(chǎng)合中迷守,非final的公有靜態(tài)字段會(huì)被不一致的方式修改。因此旺入,類必須不能包含非final的公有靜態(tài)字段兑凿。

符合規(guī)則的案例:

public static final FuncLoader m_functions;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者

  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茵瘾,隨后出現(xiàn)的幾起案子礼华,更是在濱河造成了極大的恐慌,老刑警劉巖拗秘,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件圣絮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雕旨,警方通過(guò)查閱死者的電腦和手機(jī)扮匠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凡涩,“玉大人餐禁,你說(shuō)我怎么就攤上這事⊥徽眨” “怎么了帮非?”我有些...
    開(kāi)封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我末盔,道長(zhǎng)筑舅,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任陨舱,我火速辦了婚禮翠拣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘游盲。我一直安慰自己误墓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布益缎。 她就那樣靜靜地躺著谜慌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪莺奔。 梳的紋絲不亂的頭發(fā)上欣范,一...
    開(kāi)封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音令哟,去河邊找鬼恼琼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛屏富,可吹牛的內(nèi)容都是我干的晴竞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼狠半,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼噩死!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起典予,我...
    開(kāi)封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤甜滨,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后瘤袖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體衣摩,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年捂敌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了艾扮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡占婉,死狀恐怖泡嘴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逆济,我是刑警寧澤酌予,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布磺箕,位于F島的核電站,受9級(jí)特大地震影響抛虫,放射性物質(zhì)發(fā)生泄漏松靡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一建椰、第九天 我趴在偏房一處隱蔽的房頂上張望雕欺。 院中可真熱鬧,春花似錦棉姐、人聲如沸屠列。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)笛洛。三九已至,卻和暖如春扭吁,著一層夾襖步出監(jiān)牢的瞬間撞蜂,已是汗流浹背炮捧。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工表鳍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留募胃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓枫吧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親宇色。 傳聞我的和親對(duì)象是個(gè)殘疾皇子九杂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容