




版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 顳部小切口除皺術(shù)聯(lián)合自體脂肪面部移植的應(yīng)用及療效評(píng)價(jià)
- 長(zhǎng)安購(gòu)物中心客戶(hù)關(guān)系管理策略?xún)?yōu)化研究
- 四川省巴中中學(xué)2024-2025學(xué)年高一下學(xué)期3月月考?xì)v史試題
- 基于深度學(xué)習(xí)的風(fēng)力發(fā)電超短期功率預(yù)測(cè)
- 金屬有機(jī)Pt(Ⅱ)配合物的合成、發(fā)光性質(zhì)及應(yīng)用研究
- 注冊(cè)制背景下永煤控股債券違約風(fēng)險(xiǎn)治理研究
- 成立心理健康臨床路徑管理委員會(huì)計(jì)劃
- 醫(yī)學(xué)重點(diǎn)學(xué)科建設(shè)與國(guó)際合作的職責(zé)
- 汽車(chē)行業(yè)新員工培訓(xùn)流程案例分享
- 太陽(yáng)能項(xiàng)目施工安全防范措施
- 巨量信息流廣告(初級(jí))營(yíng)銷(xiāo)師認(rèn)證考試題及答案
- 《黃磷尾氣發(fā)電鍋爐大氣污染物排放標(biāo)準(zhǔn)》
- 學(xué)校食堂食品安全培訓(xùn)課件
- 醫(yī)療信息化與成本-洞察分析
- 《建設(shè)工程施工合同(示范文本)》(GF-2017-0201)
- 2023年非車(chē)險(xiǎn)核??荚囌骖}模擬匯編(共396題)
- 陜西省西安市鐵一中2024-2025學(xué)年七年級(jí)上學(xué)期英語(yǔ)期中考試英語(yǔ)卷
- 園林花卉 課件 第五章 室內(nèi)花卉
- 2024年事業(yè)單位考試題庫(kù)及答案(共200題)
- DB65-T 4751-2023 重大活動(dòng)氣象服務(wù)規(guī)范
- 水工維護(hù)高級(jí)工技能鑒定理論考試題庫(kù)(含答案)
評(píng)論
0/150
提交評(píng)論