Java安全與質(zhì)量編碼規(guī)范_第1頁(yè)
Java安全與質(zhì)量編碼規(guī)范_第2頁(yè)
Java安全與質(zhì)量編碼規(guī)范_第3頁(yè)
Java安全與質(zhì)量編碼規(guī)范_第4頁(yè)
Java安全與質(zhì)量編碼規(guī)范_第5頁(yè)
已閱讀5頁(yè),還剩42頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1.引言

為提高Java應(yīng)用系統(tǒng)的整體質(zhì)量與安全水平,特制定本編碼規(guī)范,用于指

導(dǎo)本行開(kāi)發(fā)團(tuán)隊(duì)編寫(xiě)更優(yōu)質(zhì)的代碼編碼,在軟件開(kāi)發(fā)生命周期的早期為Java應(yīng)

用系統(tǒng)提供質(zhì)量和安全保障。

2.參考文獻(xiàn)

JAVA語(yǔ)言編碼規(guī)范《JavaCodingStyleGuide》

開(kāi)放式Web應(yīng)用程序安全項(xiàng)目標(biāo)準(zhǔn)十大安全問(wèn)題《OWASPTop10-2017》

3.術(shù)語(yǔ)

?“正例”

指正確的代碼編寫(xiě)示例,可作為對(duì)應(yīng)漏洞的修復(fù)或規(guī)避的參考示例(不是唯

一的代碼安全編寫(xiě)方式)。

?“反例”

指錯(cuò)誤的代碼編寫(xiě)方式,這些示例會(huì)產(chǎn)生對(duì)應(yīng)的質(zhì)量或安全問(wèn)題,同時(shí)會(huì)被

代碼掃描檢測(cè)出來(lái)。

■“強(qiáng)制”

指必須按照對(duì)應(yīng)規(guī)范條目要求編碼,否則無(wú)法通過(guò)代碼審計(jì)。

?“推薦”

指推薦按照對(duì)應(yīng)的規(guī)范條目要求編碼,對(duì)不同類(lèi)型的系統(tǒng)或者不同的場(chǎng)景有

著不同的要求,詳見(jiàn)具體規(guī)范條目?jī)?nèi)容加粗說(shuō)明。

?“建議”

指建議規(guī)范的代碼編寫(xiě)要求,按照對(duì)應(yīng)要求編寫(xiě)代碼可提高代碼的性能、健

壯性或安全性等等,但不做強(qiáng)制要求。

4.適用范圍

3.1適用代碼

本規(guī)范適用于本行所有采用Java語(yǔ)言開(kāi)發(fā)的應(yīng)用系統(tǒng)擁有源代碼的部分。

本規(guī)范由開(kāi)發(fā)中心修訂,依據(jù)應(yīng)用系統(tǒng)質(zhì)量與安全形勢(shì)、管理要求的變化適

時(shí)修訂和更新。

3.2系統(tǒng)分類(lèi)及規(guī)范約束要求

序號(hào)系統(tǒng)分類(lèi)特征規(guī)范約束

1外網(wǎng)系統(tǒng)用于外網(wǎng)用戶(hù)使用的Browser/Server架構(gòu)的系強(qiáng)制、推薦

統(tǒng),如網(wǎng)銀系統(tǒng)

2內(nèi)網(wǎng)系統(tǒng)用于內(nèi)網(wǎng)業(yè)務(wù)人員使用的系統(tǒng),如客服系統(tǒng)強(qiáng)制、推薦

(6.3.1除外)

3后臺(tái)系統(tǒng)沒(méi)有用戶(hù)界面,或者有用戶(hù)界面但僅供開(kāi)發(fā)運(yùn)維強(qiáng)制

人員作為數(shù)據(jù)維護(hù)的內(nèi)網(wǎng)系統(tǒng),如新核心系統(tǒng)

說(shuō)明:“規(guī)范約束”是指對(duì)應(yīng)分類(lèi)的系統(tǒng),強(qiáng)制要求遵守的規(guī)范類(lèi)別

5.規(guī)范格式

5.1注釋規(guī)范

1、類(lèi)、類(lèi)屬性、類(lèi)方法的注釋使用Javadoc規(guī)范,使用/**內(nèi)容*/格式,不

得使用〃XXX方式。

說(shuō)明:在IDE編輯窗口中,Javadoc方式會(huì)提示相關(guān)注釋?zhuān)蒍avadoc

可以正確輸出相應(yīng)注釋?zhuān)辉贗DE中,工程調(diào)用方法時(shí),不進(jìn)入方法即可懸浮提

示方法、參數(shù)、返回值的意義,提高閱讀效率。

2、抽象方法(包括接口中的方法)用Javadoc注釋?zhuān)朔祷刂?、參?shù)、

異常說(shuō)明外,還必須指出該方法做什么事情,實(shí)現(xiàn)什么功能。

說(shuō)明:對(duì)子類(lèi)的實(shí)現(xiàn)要求,或者調(diào)用注意事項(xiàng),清一并說(shuō)明。

3、類(lèi)應(yīng)添加創(chuàng)建者和創(chuàng)建日期;

4、方法內(nèi)部單行注釋在被注釋語(yǔ)句上方另起一行,使用〃注釋。方法內(nèi)部

多行注釋使用/**/注釋?zhuān)⒁馀c代碼對(duì)齊。

5、枚舉類(lèi)型字段要有注釋?zhuān)⒄f(shuō)明每個(gè)數(shù)據(jù)項(xiàng)的用途。

6、注釋要具有較好的可讀性;

反例:“TCP連接超時(shí)〃解釋成〃傳輸控制協(xié)議連接超時(shí)〃,理解反而費(fèi)腦筋。

7、代碼修改的同時(shí),注釋也要進(jìn)行相應(yīng)的修改,尤其是參數(shù)、返回值、異

常、核心邏輯等的修改。

8、代碼應(yīng)當(dāng)有20%以上的注釋率,適當(dāng)?shù)淖⑨屄誓軌虼蟠筇岣叽a的可讀

性,便于維護(hù)。

5.2命名規(guī)范

1,類(lèi)的命名應(yīng)遵守駝峰法則:所有組合單詞首字母大寫(xiě)。

示例:publicclassTestClass{……}。

2、方法的命名應(yīng)遵守駝峰法則:方法首字母小寫(xiě),其余組合單詞首字母大

寫(xiě)。

示例:publicStringgetllserName(){}

3、包名統(tǒng)一使用小寫(xiě),點(diǎn)分隔符之間有且僅有一個(gè)自然語(yǔ)義的英語(yǔ)單詞。

包名統(tǒng)一使用單數(shù)形式,但是類(lèi)名如果有復(fù)數(shù)含義,類(lèi)名可以使用復(fù)數(shù)形式。

示仞J:com.zzbank.ai.util

4、靜態(tài)常量的命名應(yīng):字母全部大寫(xiě),單詞間通過(guò)下劃線連接。

示例:publicstaticfinalStringSYSTEM_TYPE=〃abc”;

5、方法的命名應(yīng)遵守駝峰法則:方法首字母小寫(xiě),其余組合單詞首字母大

寫(xiě)。

示彳列:StringuserName;

6.安全性

5.1認(rèn)證與授權(quán)

5.1.1密碼管理

禁止將密碼硬編碼在代碼中。應(yīng)以以下方式使用:

1、用戶(hù)密碼應(yīng)以密文方式存儲(chǔ)到數(shù)據(jù)庫(kù)中;

2、與外部通訊的接口密碼應(yīng)加密存儲(chǔ)到服務(wù)器的配置文件中。

反例

Stringpassword=〃123456〃;

5.1.2密碼具有足夠的強(qiáng)度

口令長(zhǎng)度至少8位且應(yīng)由數(shù)字、字母(區(qū)分大小寫(xiě))和特殊字符組成。

說(shuō)明:較短的口令與復(fù)雜度不充分的口令容易在較短時(shí)間(較低成本)下被

破解。需要在程序中對(duì)密碼字符串的長(zhǎng)度和字符復(fù)雜度作檢查。

5.1.3密碼定期更新

應(yīng)定期提示用戶(hù)更換口令。

說(shuō)明:更換時(shí)需注意提示用戶(hù)不能再次使用最近使用過(guò)的口令,同時(shí)可降低

系統(tǒng)被撞庫(kù)攻擊的成功率。

5.1.4密碼分級(jí)使用

安全等級(jí)不同的系統(tǒng)間,同一個(gè)體的賬戶(hù)不應(yīng)使用相同的口令。

說(shuō)明:防止因安全等級(jí)低的系統(tǒng)導(dǎo)致口令泄露導(dǎo)致安全等級(jí)高的系統(tǒng)受到撞

庫(kù)攻擊。

5.1.5密碼加密建議

建議使用非對(duì)稱(chēng)加密方式加密密碼,如果一定要使用MD5等單向哈希算法,

必須添加隨機(jī)的鹽值。

正例

publicvoidUse_of_a_One_Way_Hash_without_a_Salt_Fix(){

Stringtext=

Stringdtext=

MessageDigestmd=MessageDigest.getlnstancef'SHA");

md.update((""+newRandom)).nextDouble()).getBytes());

byte[]dbts=md.digest(text.getBytes());

dtext=newString(dbts);

)

反例

publicvoidUse_of_a_One_Way_Hash_without_a_Salt(){

Stringtext="H;

Stringdtext=

MessageDigestmd=MessageDigest.getlnstancef'SHA");

byte[]dbts=md.digest(text.getBytes());

dtext=newString(dbts);

)

5.2數(shù)據(jù)庫(kù)安全

5.1.6關(guān)鍵數(shù)據(jù)管理

1、數(shù)據(jù)庫(kù)連接字符串應(yīng)以密文方式存儲(chǔ)到服務(wù)器的配置文件中。

2、數(shù)據(jù)庫(kù)服務(wù)器地址、數(shù)據(jù)庫(kù)名、用戶(hù)名、密碼(強(qiáng)制)及其他關(guān)鍵參數(shù)

應(yīng)加密存儲(chǔ)。

反例

connection=DriverManager.getConnectionf

"jdbc:oracle:thin:@3:8001:orcl;"admin","admin");

5.1.7防止SQL注入

1、外來(lái)字符串不應(yīng)動(dòng)態(tài)拼接到SQL語(yǔ)句中。

正例

Stringusername=request.getParameter("username");

Stringpassword=request.getParameter("password");

StringencryptedPass=Passwordlltil.encrypt(password);

Stringsql="selecttop1*fromuserswhere"

+"username=?andpassword=?";

PreparedStatements=c.prepareStatement(sql);

s.setString(l,username);

s.setString(2,encryptedPass);

ResultSetrs=s.executeQuery();

反例

Stringusername=request.getParameterf'username");

Stringpassword=request.getParameter("password");

StringencryptedPass=PasswordUtiLencrypt(password);

Stringsql="selecttop1*fromuserswhereusername=

+username+andpassword=

+encryptedPass+

Statements=c.createStatement();

ResultSetrs=s.executeQuery(sql);

2、ibatis和1\/^^次中$的實(shí)際作用為字符串拼接,而#的實(shí)際作用是變量替

換,因此,使用ibatis和Mybatis時(shí)動(dòng)態(tài)參數(shù)應(yīng)使用#而不是$。

正例

<dynamicprepend="where">

<isParameterPresent>

<isNotEmptyprepend="and"property="onShelves">

p.onshelves=#onShelves#

</isNotEmpty>

</isParameterPresent>

</dynamic>

反例

<dynamicprepend="where">

<isParameterPresent>

<isNotEmptyprepend="and"property="onShelves">

p.onshelves=$onShelves$

</isNotEmpty>

</isParameterPresent>

</dynamic>

5.1.8數(shù)據(jù)庫(kù)數(shù)據(jù)分級(jí)存儲(chǔ)管理

分級(jí)分權(quán)限管理數(shù)據(jù)中存儲(chǔ)的數(shù)據(jù),同時(shí)在關(guān)鍵數(shù)據(jù)查詢(xún)、修改、刪除等操

作時(shí),應(yīng)同時(shí)驗(yàn)證身份和權(quán)限。

5.3敏感信息泄露

5.2.1不要在注釋中寫(xiě)敏感信息

不要在代碼注釋中標(biāo)注如:用戶(hù)名、密碼、機(jī)器名或敏感文件位置等信息,

可使用JSP注釋代替HTML注釋。

反例

//Defaultusernamefordatabaseconnectionis"scott"

//Defaultpasswordfordatabaseconnectionis"tiger"

5.2.2不要直接明文顯示敏感信息

避免在頁(yè)面顯示隱私數(shù)據(jù),需要顯示時(shí)可根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景,在服務(wù)端對(duì)可

做隱藏處理的隱私數(shù)據(jù)隱藏后再顯示。如,將密碼處理為******。

5.2.3不要明文輸出敏感信息

隱私數(shù)據(jù)原則上不應(yīng)明文導(dǎo)出到系統(tǒng)外部文件中,系統(tǒng)間交互的文件接口若

包含隱私數(shù)據(jù),應(yīng)不寫(xiě)入或加密后再寫(xiě)入防范隱私泄露。

5.2.4防止異常泄露信息

1、JSP頁(yè)面應(yīng)指定錯(cuò)誤處理頁(yè)面。

正例

<%@pagelanguage="java"import="java.util.*"pageEncoding="utf-8"

errorPage="error.html"%>

注意:需確保錯(cuò)誤頁(yè)在任何情況下都不會(huì)發(fā)生異常。

2、Servlet層應(yīng)捕獲所有異常。

正例

publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)

throwsServletException,lOException{

try(

//……

}catch(Exceptione){

response.sendRedirect("error.html?"+SecureRandom.nextDoubleO);

)

3、應(yīng)用程序應(yīng)配置為所有頁(yè)面異常配置跳轉(zhuǎn)錯(cuò)誤頁(yè)。

4、不應(yīng)在程序中直接拋出異常的詳細(xì)信息,其中可能會(huì)包含系統(tǒng)相關(guān)的重

要信息。

說(shuō)明:不應(yīng)直接使用語(yǔ)言自有的異常處理類(lèi)進(jìn)行異常處理,應(yīng)使用應(yīng)用程序

自定義的異常類(lèi)進(jìn)行異常處理,不應(yīng)在程序中直接拋出過(guò)于詳細(xì)的異常信息。

語(yǔ)言自有的異常處理類(lèi)的命名往往可以明確指出與該異常相關(guān)的技術(shù)和接

口,這些信息都是完全公開(kāi)的。當(dāng)應(yīng)用程序?qū)⑦@樣的異常名稱(chēng)暴露后就會(huì)暴露程

序結(jié)構(gòu)甚至異常源所包含的數(shù)據(jù)。

5.2.5防止日志泄露信息

日志內(nèi)容應(yīng)分類(lèi)處理,密碼等敏感信息不要明文寫(xiě)入日志。

正例

Stringpassword=getPasswordf);

dbmsLog.println(id+":"+":"+type+":"+tstamp);

反例

Stringpassword=getPasswordf);

dbmsLog.println(id+":"+password+":"+type+":"+tstamp);

5.2.6不推薦用于加密的算法

不推薦使用DES、MD5、SHA1處理敏感信息,如密碼、秘鑰等。

5.4輸入驗(yàn)證

5.2.7輸入驗(yàn)證要求

不要完全依賴(lài)客戶(hù)端的驗(yàn)證,任何客戶(hù)端的驗(yàn)證機(jī)制(數(shù)據(jù)校驗(yàn)、身份認(rèn)證

等)都可以被繞過(guò),應(yīng)當(dāng)在服務(wù)端再次驗(yàn)證;

5.2.8防止代碼注入

1、外部輸入不應(yīng)參與類(lèi)的動(dòng)態(tài)加載,如果必須這樣做時(shí),應(yīng)對(duì)外部輸入做

白名單驗(yàn)證。

正例

Map<String,Class<??whiteClassList=DynamicUtil.getClassListf);

StringclassName=request.getParameterl^typeName^);

Objectobj=null;

if(whiteClassList.containsKey(className)){

obj=whiteClassList.get(className).newlnstance();

}

反例

StringclassName=request.getParameter(//typeName/,);

Objectobj=Class.forName(className).newlnstance();

2、外部輸入不應(yīng)參與方法的動(dòng)態(tài)執(zhí)行,如果必須這樣做時(shí),應(yīng)對(duì)外部輸入

做白名單驗(yàn)證。

正例

Map<String,Method>whiteMethodList=DynamicUtil.getMethodList();

StringclassName=request.getParameter("typeName〃);

StringmethodName=request.getParameter(//method/,);

methodName=className++methodName;

Methodmethod=null;

if(whiteMethodList.containsKey(methodName)){

method=whiteMethodList.get(methodName);

)

反例

StringclassName=request.getParameter("typeName〃);

StringmethodName=request.getParameter(z/method/,);

Methodmethod=Class.forName(className).getMethod(methodName,null);

說(shuō)明:動(dòng)態(tài)執(zhí)行相當(dāng)于直接編程,當(dāng)非預(yù)期的字符串進(jìn)入動(dòng)態(tài)執(zhí)行接口時(shí),

可能導(dǎo)致事先存在的木馬程序(由運(yùn)行環(huán)境問(wèn)題、第三方庫(kù)來(lái)源不當(dāng)?shù)葘?dǎo)致被植

入惡意代碼,這些代碼通常情況下不會(huì)被使用)被激活,從而導(dǎo)致程序被攻擊者

操控造成極大損失。

因此,對(duì)有動(dòng)態(tài)執(zhí)行需求的程序應(yīng)嚴(yán)格限制其執(zhí)行范圍,可使用沙箱、自定

義ClassLoader>自定義動(dòng)態(tài)資源集合(Key-Value集合)或代理池的方式來(lái)控制

執(zhí)行范圍以規(guī)避該漏洞的產(chǎn)生,以防止非預(yù)期的程序被執(zhí)行C

5.2.9防止命令注入

1、外來(lái)數(shù)據(jù)作為Command命令的程序名時(shí)應(yīng)作嚴(yán)格的可執(zhí)行范圍控制。

即:外來(lái)數(shù)據(jù)僅作為執(zhí)行命令的文件名(不包含路徑及參數(shù));程序指定固

定的文件夾作為執(zhí)行命令程序的路徑并自動(dòng)補(bǔ)充到Command命令字符串中。

正例

StringexeName=request.getParameter("cmd〃);

StringexeDir=ConfigUtiLgetExedirf);

exeName=CommandUtil.forName(exeDir);〃去除路徑分隔符、危險(xiǎn)字符、空格和

引號(hào)

Runtime.getRuntime().exec(exedir+exeName);

2、外來(lái)數(shù)據(jù)作為Command命令的參數(shù)時(shí)應(yīng)作嚴(yán)格的字符處理。

即:參數(shù)為字符串的應(yīng)去除字符串中的引號(hào)并在構(gòu)造Command命令字符串

時(shí)將其放入一對(duì)雙引號(hào)之間;參數(shù)值不為字符串的應(yīng)使用對(duì)應(yīng)的類(lèi)型進(jìn)行轉(zhuǎn)換校

驗(yàn)或格式校驗(yàn);最終的Command命令應(yīng)該在程序中重構(gòu),不要讓外來(lái)數(shù)據(jù)控制

命令的結(jié)構(gòu)。

正例

Stringarg=request.getParameter(z/argNamew);

arg=CommandUtil.forArg(arg);〃字符串類(lèi)參數(shù)應(yīng)去除引號(hào)

Runtime.getRuntime().exec(exedir+exeName+"+arg+

說(shuō)明:默認(rèn)情況下,命令行環(huán)境中允許執(zhí)行一些比較危險(xiǎn)的命令(如,關(guān)機(jī)、

創(chuàng)建賬戶(hù)、開(kāi)放端口、刪改文件等)。當(dāng)程序執(zhí)行構(gòu)造命令行命令包含外來(lái)數(shù)據(jù)

時(shí),外來(lái)數(shù)據(jù)可以通過(guò)分號(hào)等特殊字符改變命令結(jié)構(gòu),額外執(zhí)行其他命令。

因此,當(dāng)外來(lái)數(shù)據(jù)參與命令行命令字符串時(shí),應(yīng)作字符過(guò)濾或執(zhí)行權(quán)限控制。

需要特別注意的危險(xiǎn)字符如下:

A、重定向操作符

例如:<,?,>(不含全角逗號(hào))

這些運(yùn)算符是把結(jié)果輸出到服務(wù)器的其他地方,〈是從文件中而不是從鍵盤(pán)

中讀入命令輸入,可能被用來(lái)繞過(guò)過(guò)濾。>是把結(jié)果重定向到文件中,而不是寫(xiě)

在命令提示符窗口中?!卑呀Y(jié)果追加到別的文本當(dāng)中,而不改變?cè)瓉?lái)的內(nèi)容。

B、管道符

例如:I

管道符可以把一個(gè)命令的輸出重定向到下一個(gè)命令的輸入,如:catfilel|

grep"string"

C>inline命令

例如:;,,,$(不含全角逗號(hào))

用來(lái)結(jié)束之前的命令,直接執(zhí)行新的命令。

D、邏輯運(yùn)算符

例如:$,&&,||(不含全角逗號(hào))

這些運(yùn)算符用來(lái)對(duì)數(shù)據(jù)進(jìn)行邏輯上的運(yùn)算。

5.2.10防止LDAP注入

外部輸入不應(yīng)參與LDAP語(yǔ)句結(jié)構(gòu)的組成,參與LDAP語(yǔ)句拼接時(shí)應(yīng)過(guò)濾危

險(xiǎn)字符。

正例

LdapContextcontext=LdapUtil.getDefaultContext();

//……

Stringusr=request.getParameterf'usr");

Stringpwd=request.getParameter("pwd");

usr=LdapUtiLforValue(usr);〃去除危險(xiǎn)字符

pwd=LdapUtil.torValue(pwd);〃去除危險(xiǎn)字符

StringsearchFilter="(&(USER="+usr+")(PASSWORD="+pwd+

context.search(searchBase,searchFilter,searchcontrols);

反例

LdapContextcontext=LdapUtil.getDefaultContext();

//……

Stringusr=request.getParameterf'usr");

Stringpwd=request.getParameter("pwd");

StringsearchFilter="(&(USER-"+usr+")(PASSWORD=U+pwd+

context.search(searchBasezsearchFilter;searchcontrols);

說(shuō)明:LDAP(LightweightDirectoryAccessProtocol)輕量級(jí)目錄訪問(wèn)協(xié)議,是一

種在線目錄訪問(wèn)協(xié)議,主要用于目錄中資源的搜索和查詢(xún),是X.500的一種簡(jiǎn)便

的實(shí)現(xiàn)。

LDAP注入是在LDAP語(yǔ)句包含外來(lái)字符串的情況下借助LDAP定義的格式字

符及運(yùn)算字符篡改原有語(yǔ)意構(gòu)成注入以達(dá)到權(quán)限提升和盜取信息的目的。

外來(lái)數(shù)據(jù)必須被轉(zhuǎn)義的危險(xiǎn)字符如下:

顯示結(jié)果描述轉(zhuǎn)義或替換

(左括號(hào)\28

)右括號(hào)\29

\反斜杠\5c

*星號(hào)\2a

/正斜杠\2f

NULL空\(chéng)00

5.2.11防止XPath注入

XPath中的外來(lái)數(shù)據(jù)應(yīng)去除特殊字符。

正例

StringloginlD-request.getParameter(wloginNamew);

Stringpassword=request.getParameter("loginPass〃);

loginlD=XPathUtil.forText(loginlD);〃去除特殊字符(正則:/A"*A;&<>()/)

password=XPathUtil.forText(password);〃去除特殊字符(正則:/A"*A;&<>()/)

StringxpathExp=7/users/user[loginlD/text()="+loginlD

+"andpassword/text()="+password

+"]/firstname/text()";

XPathFactoryfactory=XPathFactory.newlnstance();

XPathxpath=factory.newXPathf);

XPathExpressionexpr=pile(xpathExp);

反例

StringloginlD=request.getParameter(zzloginName/,);

Stringpassword=request.getParameter(/zloginPassw);

〃若loginlD和password實(shí)際輸入為or1=1or=

〃則表達(dá)式將始終為true且打印所有用戶(hù)的firstname

StringxpathExp='7/users/user[loginlD/text()="+loginlD

+"andpassword/text()="+password

+"]/firstname/text()";

XPathFactoryfactory=XPathFactory.newlnstance();

XPathxpath=factory.newXPath();

XPathExpressionexpr=pile(xpathExp);

說(shuō)明:XPath(XmlPathLanguage)為解析XML數(shù)據(jù)的查詢(xún)語(yǔ)言(類(lèi)似SQL語(yǔ)言)。

當(dāng)外來(lái)字符串直接拼接到XPath查詢(xún)字符串中時(shí),可能導(dǎo)致原有查詢(xún)語(yǔ)句的語(yǔ)意

被篡改,造成無(wú)效的驗(yàn)證、數(shù)據(jù)泄露、數(shù)據(jù)丟失等后果。

需注意的字符集的正則表達(dá)式為/仙*勺&<>()/

5.2.12防止資源注入

1,Socket通訊端口不應(yīng)使用外來(lái)數(shù)據(jù)。

正例

intport=ConfigUtiLgetlnteger(/zsocket.root.portw);

ServerSocketsrvr=newServerSocket(port);

反例

intport=lnteger.parselnt(request.getParameter(z/portw));

ServerSocketsrvr=newServerSocket(port);

2、獲取服務(wù)器文件資源時(shí)不應(yīng)使用外來(lái)數(shù)據(jù)作為資源路徑,應(yīng)使用白名單

或資源路徑池的方式限制可動(dòng)態(tài)獲取的范圍。

正例

Stringpath=request.getParameterf'path");

Inputstreamins=null;

if(ResourceUtil.access(path))(//不在白名單或資源池范圍內(nèi)時(shí)返回false

ServletContextcontext=session.getServletContext();

Ins=context.getResourceAsStream(path);

)

反例

Stringpath=request.getParameterf'path");

ServletContextcontext=session.getServletContext();

Inputstreamins=context.getResourceAsStream(path);

說(shuō)明:當(dāng)程序定義的資源類(lèi)型或位置來(lái)源與于外來(lái)數(shù)據(jù)(如文件路徑或端口

號(hào))時(shí),則會(huì)在這個(gè)外來(lái)數(shù)據(jù)的控制下執(zhí)行或訪問(wèn)非預(yù)期的資源,從而導(dǎo)致邏輯

問(wèn)題或數(shù)據(jù)泄露問(wèn)題。如在文件系統(tǒng)環(huán)境中,外來(lái)數(shù)據(jù)中包含.,/,\(小數(shù)點(diǎn),

斜杠,反斜杠)這些特殊字符時(shí)就會(huì)導(dǎo)致路徑遍歷問(wèn)題。而若Socket的端口由

外來(lái)數(shù)據(jù)控制時(shí)則直接導(dǎo)致通訊端口被篡改。

5.2.13防止路徑遍歷

1、外來(lái)數(shù)據(jù)不應(yīng)作為文件訪問(wèn)的絕對(duì)路徑。

2、外來(lái)數(shù)據(jù)作為文件訪問(wèn)的相對(duì)路徑時(shí),應(yīng)去除“%00”及、0'。

說(shuō)明:或的出現(xiàn)會(huì)提高目錄層級(jí),當(dāng)提高到根目錄時(shí),相當(dāng)于

外來(lái)數(shù)據(jù)直接作為絕對(duì)路徑;

“%00”或i\0,的出現(xiàn)(即,null字符)會(huì)中斷文件名,導(dǎo)致操作系統(tǒng)丟

棄該字符之后的字符串,從而使代碼中根據(jù)文件名判斷文件類(lèi)型的邏輯失效。

3、上傳文件應(yīng)對(duì)其類(lèi)型進(jìn)行驗(yàn)證,且外來(lái)數(shù)據(jù)作為文件名時(shí),應(yīng)去除

“%00”及"\0\

說(shuō)明:構(gòu)成文件路徑的字符串包含外來(lái)數(shù)據(jù)時(shí),若外來(lái)數(shù)據(jù)包含特殊字符,

則會(huì)造成文件路徑被篡改到其他位置或非授權(quán)類(lèi)型文件被上傳或下載??赡茉斐?/p>

系統(tǒng)文件被損壞、篡改、竊取。

外來(lái)數(shù)據(jù)可以通過(guò)字符串中的“可造成目錄次序的改變從而改變目錄結(jié)

構(gòu),或被直接用作絕對(duì)路徑時(shí)就可以訪問(wèn)任意文件和目錄,包括應(yīng)用程序文件、

配置文件及操作系統(tǒng)關(guān)鍵文件。當(dāng)沒(méi)有在操作系統(tǒng)中對(duì)應(yīng)用的執(zhí)行賬戶(hù)權(quán)限及關(guān)

鍵目錄權(quán)限作控制時(shí),就會(huì)造成義件篡改、信息泄露等問(wèn)題。路徑遍歷(Path

Traversal)也叫"dot-dot-slash〃、/'directorytraversal"、/"directoryclimbing”或

“backtracking”。

5.2.14防止參數(shù)篡改

盡量避免使用頁(yè)面隱藏域及頁(yè)面緩存保存關(guān)鍵數(shù)據(jù)。

1、避免濫用頁(yè)面隱藏域:頁(yè)面隱藏域中的數(shù)據(jù)在被提交到服務(wù)端時(shí)需重新

驗(yàn)證。

說(shuō)明:如下拉選擇框等方式傳入的數(shù)據(jù)可做白名單驗(yàn)證,重要參數(shù)如價(jià)格等

不要使用隱藏表單字段的方式從客戶(hù)端獲取。

2、頁(yè)面不需要的數(shù)據(jù)不應(yīng)傳遞到頁(yè)面請(qǐng)求響應(yīng)中。

說(shuō)明:特別需要避免直接將所有數(shù)據(jù)封裝到j(luò)son并傳遞到前端。

參數(shù)篡改攻擊是基于網(wǎng)絡(luò)數(shù)據(jù)交換的客戶(hù)端和服務(wù)器之間以修改應(yīng)用程序

數(shù)據(jù)的操作參數(shù),如用戶(hù)認(rèn)證和權(quán)限,產(chǎn)品的價(jià)格和數(shù)量,等。通常,這些信息

存儲(chǔ)在cookies,隱藏的表單字段,或URL查詢(xún)字符串,并用于提高應(yīng)用程序的

功能和控制。

5.5輸出驗(yàn)證

5.2.15防止跨站腳本

1、${}表達(dá)式的默認(rèn)實(shí)現(xiàn)不能防止XSS攻擊,因此在使用時(shí)應(yīng)對(duì)其默認(rèn)實(shí)現(xiàn)

進(jìn)行修改,使其具有XSS轉(zhuǎn)義功能。

注意,修改此默認(rèn)實(shí)現(xiàn)會(huì)導(dǎo)致需要輸出HTML時(shí)無(wú)法正常輸出,故需與jstl、

struts等標(biāo)簽配合使用。

正例

<c:outvalue="${outerStringKey}"/>

2、<%=%>在使用時(shí)應(yīng)使用XSS過(guò)濾函數(shù)對(duì)輸出字符串作XSS轉(zhuǎn)義處理。

正例

<%=XSSFilter.forText(outerStringValue)%>

3、明確不需要輸出HTML時(shí)應(yīng)保持struts的property標(biāo)簽的escape屬性為

true。

說(shuō)明:escape屬性默認(rèn)為true即不論是什么格式的數(shù)據(jù)都作為HTML普通

顯示文本輸出,當(dāng)設(shè)置為false時(shí)則會(huì)識(shí)別HTML字符。

4、Servlet中自行構(gòu)造頁(yè)面輸出時(shí),應(yīng)對(duì)參與HTML文本構(gòu)造的外部輸入字

符串作對(duì)應(yīng)的處理。

正例

StringBufferhtml-newStringBuffer();

//……

html.append(XSSFilter.forText(userlnputString_Text));

//……

html.append(XSSFilter.forHTML(userlnputString_HTML));

//……

response.getWriter().print(html.toString());

5.2.16防止HTTP響應(yīng)折斷

在操作HTTP報(bào)頭(即Head部分)時(shí),所有寫(xiě)入該區(qū)域的外部數(shù)據(jù)必須去

除V和\n字符。

正例

publicvoidsplittingFix(HttpServletRequestrequest,HttpServletResponseresponse){

Stringtext=request.getParameterf'text");

text=text.replace("\n",

text=text.replace("\r",

response.setHeader("text",text);

}

反例

publicvoidsplittingRes(HttpServletRequestrequest,HttpServletResponseresponse){

Stringtext=request.getParameter("text");

response.setHeaderC'texf',text);

}

5.2.17避免開(kāi)放式跳轉(zhuǎn)

外部獲取的字符串作為URL或URL的一部分時(shí)應(yīng)對(duì)最終的URL進(jìn)行安全校

驗(yàn)。

當(dāng)外來(lái)數(shù)據(jù)被用作跳轉(zhuǎn)地址時(shí),可能會(huì)發(fā)生網(wǎng)絡(luò)釣魚(yú)甚至注入類(lèi)攻擊。

可編寫(xiě)名為checkUrl或testUrl函數(shù)對(duì)最終url進(jìn)行安全校驗(yàn)。

說(shuō)明:校驗(yàn)規(guī)則按程序設(shè)計(jì)自行制定,校驗(yàn)策略需以白名單為主。

正例

Stringurl=checkUrl(request.getParameter(/,url,/));

response.sendRedirect(url);

反例

Stringurl=request.getParameter(^urK);

response.sendRedirect(url);

5.6配置問(wèn)題

5.2.18Proxy設(shè)置建議

對(duì)每個(gè)需要轉(zhuǎn)發(fā)的請(qǐng)求分別設(shè)置代理,而不是將所有http\https請(qǐng)求都轉(zhuǎn)發(fā)

到代理服務(wù)器上;

正例

publicstaticvoidmain(String[]args){

try{

URLurl=newURL("http://www.baidu.com");

InetSocketAddressaddr=newInetSocketAddress("54",8080);

Proxyproxy=newProxy(Proxy.Type.HTTP,addr);

URLConnectionconn=url.openConnection(proxy);

Inputstreamin=conn.getlnputstream();

Strings=lOUtils.toString(in);

System.out.println(s);

}catch(Exceptione){

e?printStackTrace();

}

}

反例

publicstaticvoidmain(String[]args){

Propertiesprop=System.getProperties();

prop?setProperty("xyHost">"192.168.0.254");

prop.setProperty("http.proxyPort"8080");

prop.setProperty("http.nonProxyHosts","localhost|192,168.0.*");

prop?setProperty("xyHost","54");

prop.setProperty("xyPort","443");

prop.setProperty("xyHost","54");

prop.setProperty("xyPort","2121");

prop.setProperty("ftp.nonProxyHosts","localhost|192,168.0.?");

prop.setProperty("socksProxyHosf^"54");

prop.setPropertyCsocksProxyPort">"8000");

}

5.2.19不要設(shè)置setAccessible為true

不要使用setAccessible為true,它讓程序員能夠允許反映對(duì)象繞過(guò)Java

accesscontrol,并反過(guò)來(lái)更改私有字段或調(diào)用私有方法、行為;

5.2.20spring的defaultHtmlEscape設(shè)置

使用spring,要設(shè)置defaultHtmlEscape屬性為true;

說(shuō)明:默認(rèn)defaultHtmlEscape是設(shè)置為false的,此時(shí)接收到的外部數(shù)據(jù)可

能不會(huì)轉(zhuǎn)義,潛在地將應(yīng)用暴露給跨站腳本攻擊,設(shè)置為true會(huì)降低此風(fēng)險(xiǎn)。

5.2.21Cookie安全配置

使用Cookie應(yīng)全面評(píng)估并最大限度降低可能存在的安全風(fēng)險(xiǎn)。建議按如下

要求使用:

1、使用Cookie時(shí)應(yīng)啟用Cookie的安全特性。

說(shuō)明:可通過(guò)設(shè)置Secure屬性為true來(lái)啟用Cookie的安全特性。

2^使用Cookie時(shí)應(yīng)指定合適的生命周期。

說(shuō)明:可通過(guò)Expire屬性設(shè)置Cookie的生命周期,當(dāng)該值為。則關(guān)閉頁(yè)面

時(shí)Cookie就會(huì)被自動(dòng)清除。

3、使用Cookie時(shí)應(yīng)設(shè)置httpOnlyCookies/httpOnly屬性為true。

說(shuō)明:可在web.xml中設(shè)置該屬性,當(dāng)該屬性為true時(shí)客戶(hù)端腳本(如

JavaScript)將無(wú)法讀取Cookie。

正例

<session-config>

<cookie-config>

<http-only>true</http-only>

</cookie-config>

</session-config>

注:該配置可以在應(yīng)用服務(wù)器進(jìn)行全局配置,具體方法請(qǐng)查詢(xún)各應(yīng)用服務(wù)器

官網(wǎng)。

4、關(guān)鍵程序邏輯不應(yīng)過(guò)分依賴(lài)于Cookie提供的數(shù)據(jù)。

說(shuō)明:如金額、數(shù)量、賬號(hào)、密碼、憑據(jù)等安全數(shù)據(jù)和敏感數(shù)據(jù)不應(yīng)以Cookie

為唯一來(lái)源。

5、使用Cookie時(shí)應(yīng)對(duì)Cookie進(jìn)行加密。

說(shuō)明:Cookie是由服務(wù)器端生成,發(fā)送給User-Agent(一般是瀏覽器),瀏

覽器會(huì)將Cookie的key/value保存到某個(gè)目錄卜的文本文件內(nèi),卜次請(qǐng)求同一網(wǎng)

站時(shí)就發(fā)送該Cookie給服務(wù)器(前提是瀏覽器設(shè)置為啟用cookie)。Cookie名稱(chēng)

和值可以由服務(wù)器端開(kāi)發(fā)自己定義,對(duì)于JSP而言也可以直接寫(xiě)入jsessionid,這

樣服務(wù)器可以知道該用戶(hù)是否是合法用戶(hù)以及是否需要重新登錄等,服務(wù)器可以

設(shè)置或讀取Cookies中包含信息,借此維護(hù)用戶(hù)跟服務(wù)器會(huì)話中的狀態(tài)。

由于Cookie存儲(chǔ)于客戶(hù)端用戶(hù)本地,因此其安全性無(wú)法得到有效保障,一

旦被篡改,所有依賴(lài)于Cookie的程序都會(huì)受到影響,這些影響可能會(huì)形成任何

注入類(lèi)安全漏洞。

5.7日志問(wèn)題

5.2.22日志分級(jí)分類(lèi)

日志內(nèi)容應(yīng)在已劃分嚴(yán)重等級(jí)后再進(jìn)行類(lèi)別劃分,并且,不同類(lèi)別的日志應(yīng)

分別輸出存儲(chǔ)到不同的位置。

5.2.23明確區(qū)分安全和業(yè)務(wù)類(lèi)日志

安全類(lèi)日志和業(yè)務(wù)類(lèi)日志中應(yīng)盡量避免出現(xiàn)程序元素。

說(shuō)明:此二類(lèi)日志若結(jié)合明確的程序或代碼元素(類(lèi)名、方法名等),一旦

泄露則會(huì)極大提升系統(tǒng)被二次攻擊的可能性。攻擊者可結(jié)合第一次攻擊反饋和業(yè)

務(wù)接口對(duì)應(yīng)的程序元素制定更明確的技術(shù)攻擊手段來(lái)提高攻擊成功率。

5.2.24明確區(qū)分安全和性能類(lèi)日志

安全類(lèi)日志和性能類(lèi)日志中應(yīng)盡量避免出現(xiàn)具體的業(yè)務(wù)數(shù)據(jù)。

說(shuō)明:此二類(lèi)日志一般會(huì)涉及第三方產(chǎn)品,即日志會(huì)在一定范圍內(nèi)擴(kuò)散。

5.2.25防止日志偽造

寫(xiě)入日志中的用戶(hù)輸入,應(yīng)進(jìn)行特殊字符過(guò)濾處理。

正例

if(loginSuccessful){

logger.severe("Userloginsucceededfor:"+replaceLog(username));

}else{

logger.severe("Userloginfailedfor:"+replaceLog(username));

)

〃過(guò)濾特殊字符

publicstaticStringreplaceLog(Stringstr){

Stringdest=

if(str!=null){

Patternp=Ppile("\\s*|\t|\r|\n");

Matcherm=p.matcher(str);

dest=m.replaceAII("");

)

returndest;

)

反例

if(loginSuccessful){

logger.severef'Userloginsucceededfor:"+username);

}else{

logger.severe("Userloginfailedfor:"+username);

)

5.2.26Logger對(duì)象應(yīng)聲明為staticfinal

類(lèi)中定義的Logger對(duì)象盡量聲明為staticfinalo

說(shuō)明:隨著所在類(lèi)實(shí)例的創(chuàng)建被多次實(shí)例化,內(nèi)存中存在多個(gè)當(dāng)前類(lèi)的日志

實(shí)例可能會(huì)導(dǎo)致當(dāng)前類(lèi)實(shí)例在處理不同業(yè)務(wù)過(guò)程中輸出的日志發(fā)生混亂,不便于

日志審查工作。

5.8會(huì)話管理

5.3.1sessionid的構(gòu)造應(yīng)由程序來(lái)生成

sessionid的構(gòu)造應(yīng)由程序自身來(lái)構(gòu)造生成,不要采用外部數(shù)據(jù)構(gòu)造。

5.3.2session銷(xiāo)毀過(guò)期建議

1、登錄系統(tǒng)驗(yàn)證成功后重置session;

2、退出系統(tǒng)后銷(xiāo)毀session;

3、session應(yīng)根據(jù)場(chǎng)景設(shè)置合理的過(guò)期時(shí)間;

正例

〃用戶(hù)身份驗(yàn)證成功后應(yīng)重構(gòu)會(huì)話。

Useruser=UserUtil.getUser(request);〃根據(jù)request傳參構(gòu)造user對(duì)象

if(LoginUtil.access(user)){〃當(dāng)?shù)卿涷?yàn)證成功時(shí)返Fltrue

session.invalidated;

//……再完善新的session

5.3.3防范跨站請(qǐng)求偽造

CSRF(Cross-siterequestforgery)跨站請(qǐng)求偽造是一類(lèi)常見(jiàn)編程漏洞。對(duì)于存在

CSRF漏洞的應(yīng)用/網(wǎng)站,攻擊者可以事先構(gòu)造好URL,只要受害者用戶(hù)訪問(wèn),后

臺(tái)便在用戶(hù)不知情的情況下充數(shù)據(jù)庫(kù)中用戶(hù)參數(shù)進(jìn)行相應(yīng)修改。

業(yè)界普遍使用的三種有效防護(hù)方案供選擇。

1)驗(yàn)證HTTPReferer字段

說(shuō)明:通過(guò)獲取HTTP中的Referer屬性判斷請(qǐng)求來(lái)源,非同源請(qǐng)求則判斷為

非法請(qǐng)求。

優(yōu)點(diǎn):Referer屬性無(wú)法被篡改;實(shí)施成本較低,只需在服務(wù)端程序部署。

缺點(diǎn):由于Referer屬性記錄了請(qǐng)求的來(lái)源,即用戶(hù)的網(wǎng)絡(luò)位置。一旦該值

被泄露則可能導(dǎo)致隱私數(shù)據(jù)泄露(如組織內(nèi)網(wǎng)信息等)。

適用場(chǎng)景:存量項(xiàng)目修復(fù)。

示例:

Stringreferer=request.getHeader("Referer");

〃判斷Referer是否以bank.example開(kāi)頭

iff(referer!=null)&&(referer.trim().startsWith(z/bank.examplez,))){

chain.doFilterfrequest,response);

}else{

request.getRequestDispatcherf^error.jsp/O-forwardlrequestresponse);

2)在請(qǐng)求地址中添加token并驗(yàn)證

優(yōu)點(diǎn):相對(duì)檢查Referer方式更加安全;不涉及隱私問(wèn)題。

缺點(diǎn):無(wú)法保證自身的安全,可通過(guò)Referer被竊取;實(shí)施成本較高,需雙

端配置。

適用場(chǎng)景:新項(xiàng)目開(kāi)發(fā),存量項(xiàng)目修復(fù)。

3)在HTTP頭中自定義屬性并驗(yàn)證

說(shuō)明:類(lèi)似token方式,不同點(diǎn)是該自定義屬性存儲(chǔ)于TTTP頭的自定義屬

性。

優(yōu)點(diǎn):由于自定義,被作為攻擊目標(biāo)的概率較低。

缺點(diǎn):實(shí)施成本極高,改動(dòng)范圍較大。

適用場(chǎng)景:新項(xiàng)目開(kāi)發(fā)。

5.3.4防范跨站歷史偽造

重定向的目標(biāo)地址必須追加充分的隨機(jī)值后綴。

正例

response.sendRedirectf'error.html?"+SecureRandom.nextDouble());

反例

response.sendRedirectf'error.html?");

說(shuō)明:SOP(Same-originpolicy)是現(xiàn)代瀏覽器的最重要的安全概念。SOP是指

通過(guò)設(shè)計(jì)不能從不同來(lái)源的網(wǎng)頁(yè)互相交流。基于SOP規(guī)定,一個(gè)絕對(duì)URI來(lái)源包

含三個(gè)要素:協(xié)議、主機(jī)、端口,當(dāng)兩個(gè)絕對(duì)URI的這三個(gè)要素的任意一項(xiàng)不相

同時(shí)即表示這兩個(gè)URI非同源。瀏覽器的history對(duì)象正是按這個(gè)規(guī)則來(lái)判斷來(lái)

源。history對(duì)象是在一個(gè)瀏覽器選項(xiàng)卡中已訪問(wèn)頁(yè)面的記錄,用戶(hù)可以通過(guò)瀏覽

器的"前進(jìn)〃和"后退〃按鈕通過(guò)history進(jìn)行跳轉(zhuǎn)。頁(yè)面包含的iframe內(nèi)發(fā)生的任何

地址變化也會(huì)被記錄到history中,但如果發(fā)生了重定向(Redirect),history只

會(huì)記錄重定向后指向的最終頁(yè)面,而相同的頁(yè)面只會(huì)在history中記錄一次。由

于SOP的限制,history中記錄的地址無(wú)法被外部獲取,但history.length屬性可

以被外部獲取。

歷史操控即跨站歷史操控(CrossSiteHistoryManipulation(XSHM)),正是由

history.length屬性的開(kāi)放性造成的,從而可能導(dǎo)致SOP的妥協(xié),造成雙向CSRF

及其他風(fēng)險(xiǎn),如:侵犯用戶(hù)隱私,登錄狀態(tài)檢測(cè)、資源映射、敏感信息推測(cè)、活

動(dòng)跟蹤和URL參數(shù)泄露。

7.框架及組件

5.9Struts使用

5.3.5生產(chǎn)環(huán)境關(guān)閉struts的devMode調(diào)試模式

Struts2.1.0-2.5.1版本,將devMode設(shè)置為true,會(huì)導(dǎo)致任意命令執(zhí)行的漏

洞。

反例

<constantname=wstruts.devModez,value=,,true,7>

5.3.6Struts2操作名稱(chēng)禁止使用通配符(*)

使用*的話,允許將操作名稱(chēng)作為OGNL表達(dá)式進(jìn)行評(píng)估,這允許攻擊者修

改會(huì)話等系統(tǒng)變量或者在服務(wù)器上執(zhí)行任意命令。

建議使用struts2.3.143以上版本,此版本修復(fù)了該問(wèn)題

反例

<actionname="*"class=,,com.acme.actions.example,,>

<result>/example/{l}.jsp<result>

<action>

5.10其他組件及接口

5.3.7程序?qū)崿F(xiàn)不應(yīng)使用JNI

JNI,JavaNativeInterface,是nativecode的編程接口。JNI使Java代碼程

序可以與nativecode交互。如,在Java程序中調(diào)用nativecode;在nativecode

中嵌入Java虛擬機(jī)調(diào)用Java的代碼。

使用JNI可以利用nativecode的平臺(tái)相關(guān)性,在平臺(tái)相關(guān)的編程中更具優(yōu)勢(shì);

可提高nativecode的復(fù)用率;nativecode可直接操作底層,提高程序執(zhí)行效率。

但川I的使用也會(huì)帶來(lái)以下問(wèn)題:

一、從Java環(huán)境到nativecode的上下文切換效率較低;

二、由于nativecode自身問(wèn)題,容易導(dǎo)致JVM崩潰;

三、nativecode中不恰當(dāng)?shù)膬?nèi)存使用容易導(dǎo)致內(nèi)存泄露。

在Java內(nèi)存定義中,nativecode的內(nèi)存操作在nativeheap中進(jìn)行,但native

heap依賴(lài)于nativecode進(jìn)行內(nèi)存釋放,java的gc機(jī)制并不會(huì)釋放nativeheap。

這樣就容易導(dǎo)致內(nèi)存泄露甚至JVM崩潰。

5.3.8避免定義和調(diào)用native成員

代碼應(yīng)盡量避免定義和調(diào)用native成員。

5.3.9避免使用己被棄用的接口

說(shuō)明:即Java中聲明為@Deprecated的Interface>Class、Method>Fieldo

這些接口被調(diào)用時(shí)一般在IDE中會(huì)有明顯的提示,如在Eclipse中會(huì)被追加刪除

線。這些接口在被棄用的同時(shí)都會(huì)發(fā)布替代接口或替代實(shí)現(xiàn)方案。

當(dāng)接口(InterfaceClass、MethodField)存在性能問(wèn)題或安全問(wèn)題時(shí),將

會(huì)在API文檔明確聲明已棄用或在代碼中聲明為@Deprecated。應(yīng)用程序使用這

樣的接口將會(huì)把這些接口本身存在的問(wèn)題轉(zhuǎn)嫁到應(yīng)用程序中,從而影響程序的性

能及安全性。而且,某些接口可能會(huì)在較新的版本中被刪除,一旦升級(jí)這些組件

將導(dǎo)致程序不可用,嚴(yán)重影響程序更新、擴(kuò)展。

5.3.10避免使用自定義Thread

Web應(yīng)用盡量避免使用使用自定義Thread,如果一定要用,不要在循環(huán)中

使用,盡量使用線程池。

說(shuō)明:在Web應(yīng)用中,不正確的Thread使用可能會(huì)導(dǎo)致異步處理、異步響

應(yīng)等違背一致性的問(wèn)題,容易造成數(shù)據(jù)混亂和邏輯混亂。

5.3.11WEB應(yīng)用避免使用System.exit

Web應(yīng)用盡量避免使用System.exit函數(shù)。

說(shuō)明:System.exit會(huì)直接終止JVM,這會(huì)導(dǎo)致未提交的事務(wù)丟失、正在進(jìn)行

的事務(wù)中斷、緩存數(shù)據(jù)丟失等重大數(shù)據(jù)問(wèn)題。因此,不推薦Web應(yīng)用和Server

端程序等一些比較復(fù)雜的程序使用該函數(shù)來(lái)終止程序。

5.3.12避免使用Socket

盡量避免使用自定義Socket通信。

說(shuō)明:直接使用Socket就意味著要自己定義通信協(xié)議,自定義的通信協(xié)議

容易存在致命的設(shè)計(jì)缺陷,而且由于自定義其不能被普遍使月,會(huì)影響程序的通

用性,降低外部交互能力。

5.3.13避免使用finalize

盡量避免在代碼中調(diào)用finalize函數(shù)。

說(shuō)明:finalize是專(zhuān)供gc機(jī)制調(diào)用的函數(shù),開(kāi)發(fā)人員不應(yīng)自行調(diào)用該函數(shù),

以免誤解造成程序異常。

5.3.14避免使用系統(tǒng)輸出流

盡量避免在代碼中使用System.out、System.err流。

系統(tǒng)輸出流主要在測(cè)試的時(shí)候使用,在生產(chǎn)環(huán)境上,如果輸出的信息沒(méi)有價(jià)

值,那么應(yīng)當(dāng)注釋或者刪除,如果有價(jià)值,則應(yīng)改寫(xiě)為日志記錄。

正例

publicclassMyClass

publicstaticvoidmain(String[]args){

Logger.logf'helloworld");

)

}

反例

publicclassMyClass

publicstaticvoidmain(String[]args){

System.out.println("helloworld");

)

}

8.編碼錯(cuò)誤

5.3比較與賦值

5.3.15不要誤用二和二=

1、應(yīng)當(dāng)使用==進(jìn)行比較的時(shí)候,不要誤用為二;

2、應(yīng)當(dāng)使用;進(jìn)行賦值的時(shí)候,不要誤用為==;

正例

if(a==l){

b=0;

)

反例

if(a=l){〃錯(cuò)誤1

b==0;〃錯(cuò)誤2

)

5.3.16字符串比較應(yīng)使用equals

字符串比較應(yīng)當(dāng)使用equals。方法,而不能直接使用==;

正例

Stringstrl="hello";

Stringstr2=newString("hello");

if(strl.equals(str2))

)

反例

Stringstrl="hello";

Stringstr2=newString("hello");

if(strl==str2)〃永遠(yuǎn)是false

(

……〃死代碼

)

說(shuō)明:用工或上來(lái)比較兩個(gè)字符串是否相等,其實(shí)質(zhì)比較的是兩個(gè)對(duì)象,

而不是字符串的值,在有些場(chǎng)景下結(jié)果永遠(yuǎn)是false的,可能導(dǎo)致邏輯錯(cuò)誤。

5.3.17浮點(diǎn)型數(shù)據(jù)不要直接進(jìn)行相等性比較

float和double型數(shù)據(jù)不要直接進(jìn)行相等性比較,應(yīng)設(shè)置合理的誤差值,比

較其差值的絕對(duì)值,在誤差范圍內(nèi)即認(rèn)為相等;

正例

publicstaticfinaldoubleMAX=0.2;

publicStringtest(doubledl,doubled2){

doubled3=dl+d2;//

if(abs(d3-MAX)<=le-6){

return"OK";

)

)

反例

publicstaticfinaldoubleMAX=0.2;

publicstringtestfdoubledl,doubled2){

doubled3=dl+d2;//

if(d3<=MAX){

return"OK";

}

}

當(dāng)dl=d2=0.1時(shí),d3=0.20000000149011612是>0.2的,程序員以為d3<=MAX是

成立的,進(jìn)行了錯(cuò)誤的處理邏輯。

5.3.18字符串與“”比較

字符串判空與〃〃做比較時(shí),應(yīng)對(duì)"〃調(diào)用equals。方法。

正例

Stringstr;

lf(/z/,.equals(str)){

)

反例

Stringstr;

lf(str.equals(/z//)){

)

5.4邏輯錯(cuò)誤問(wèn)題

5.4.1避免被0除

變量作為除數(shù)時(shí),應(yīng)保證其值不會(huì)為0;

正例

publicintTEST(inttotal,intnum)throwsArithmeticException

(

if(numRequests!=0){

returntotal/num;

}else{

Logger.log("被0除!”);

throwArithmeticException;

}

)

反例

publicintTEST(inttotal,intnum)

{

returntotal/num;

}

5.4.2避免表達(dá)式恒為false

if和while語(yǔ)句的判斷條件,需要保證其值是根據(jù)業(yè)務(wù)場(chǎng)景動(dòng)態(tài)變化的,而

不恒定為false,否則語(yǔ)句將永遠(yuǎn)不會(huì)被執(zhí)行;

正例

boolflag=false;

〃根據(jù)場(chǎng)景,為flag賦予新值。

If(flag)

(

....〃死代碼

)

else

(

〃永遠(yuǎn)只執(zhí)行這段代碼

)

反例

lf(flag=false)

{

....〃死代碼

)

else

{

〃永遠(yuǎn)只執(zhí)行這段代碼

)

5.4.3保證switch語(yǔ)句完整

1>每個(gè)switch語(yǔ)句都應(yīng)包含default塊,case語(yǔ)句為完全考慮的情況進(jìn)行處

理,否則可能由于未處理的情況導(dǎo)致程序異常,尤其是判斷變量來(lái)源于外部時(shí);

2^每個(gè)case,都應(yīng)以break結(jié)束;

正例

switch(num)

{

case1:

str="a";

break;

case2:

str="b";

break;

default:

str=”請(qǐng)輸入正確的值/

break;

)

反例

switch(num)

(

case1:

str="a";〃缺失了treak

case2:

str="b";〃缺失了break

〃缺失了default

}

5.4.4不要在finally語(yǔ)句中return

finally語(yǔ)句中,不要寫(xiě)return語(yǔ)句,否則可能導(dǎo)致異常未處理,甚至是邏輯

出錯(cuò);

反例

publicstaticinttestFinallyfinti)throwsException

(

try{

if(i<0){

thrownewD

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論