fortify程式碼掃描問題結果分析
最近專案的程式碼使用fortify工具掃描了一下,發現了專案中存在的一些問題,在以後程式碼編寫的過程中要注意,避免出現類似的錯誤。
以下為本次程式碼分析工具FORTIFY對程式碼的分析結果。這些問題雖然古老、簡單然而經典,也是需要引起重視。
程式碼問題主要集中在如下類別:存在安全隱患、存在資源洩漏隱患、序列化問題、字串比較、異常處理問題,以及其它一些BAD PRACTICE和粗心引起的問題。
J2EE Bad Practices: Non-Serializable Object Stored in Session (Time and State, Structural)
把一個不可序列化的物件作為
程式碼示例
SharerInfo sharerInfo = new SharerInfo();
getServletRequest().getSession().setAttribute( “sharerInfo”, shareInfo);
其中SharerInfo類沒有實現序列化(implements java.io.Serializable)
分析
對於不需要將物件序列化到同一jvm以外的應用場景,以上程式碼沒有問題。然而考慮到系統的擴充套件性,以上問題應該予以避免。
以下是一些常見的會導致問題的場景:
1.將
在一些大型應用系統的實現裡,會考慮將部分SESSION裡的物件鈍化到資料庫、磁盤裡。
2.叢集環境
在非session-sticky的叢集環境裡,應用伺服器會在叢集裡廣播、複製session資料
修正
ShareInfo類應該實現序列化:implements java.io.Serializable
Unreleased Resource
程式可能無法成功釋放某一項系統資源
程式碼示例
Try {
Connection con = jdbcTemplate.getDataSource().getConnection();
}
Catch(Exception e) {
// Handle exception
}
Con.close();
分析
系統資源比如資料庫資源(Connection ,Statement,etc),IO資源(InputStream,OutputStream,etc)都是有限的,如果沒有正確的釋放掉,就會出現資源洩漏的問題。常見的後果如出現數據庫連線池無可用連線(pool exhausted),Too many open files等
修正
將資源釋放程式碼放到finally塊中進行
Mutable static field
將業務上不可變的靜態值作為非final屬性直接暴露給呼叫者
程式碼示例
public staticStringREALM;
static {
REALM=bundle.getMessage("realm",null,DEFAULT_LOCALE);
}
分析
在業務上REALM是常量。但這樣直接將REAM作為非FINAL靜態屬性暴露給呼叫者,容易導致靜態屬性值被修外部呼叫者修改,從而導致系統問題。
修正
將realm定義為final型別或者通過getRealm方法暴露介面,而隱藏setRealm方法。
Dropped or ignored exception
異常不做任何處理直接忽略
程式碼示例
Try {
//handle logic
}
Catch (Exception e) { }//do nothing
分析
將異常捕獲後直接忽略是一種BAD PRACTICE.
修正
如果需要處理異常(比如列印異常資訊),則進行處理。如果不需要,則繼續丟擲異常給更外層的呼叫者
直接將資訊輸出到標準輸出
這是一種BAD PRACTICE。嚴重的情況下還會對系統性能造成衝擊。
程式碼示例
System.out.print
e.printStackTrace.
分析
以上是兩種常見的不被推薦的列印資訊的程式碼例子。
修正
雖然可以通過修改系統屬性或者修改System.out的輸出屬性來改變System.out.print等方法的輸出目標。但更建議直接禁止這種寫法。
通過LOG4J等LOG工具包將資訊按資訊級別輸出到外部系統(磁碟、資料庫,甚至其它伺服器比如通過JMS將日誌傳送給日誌伺服器)。
如果想獲取異常堆疊資訊(e.printStackTrace),可以利用如下helper程式碼捕獲整個異常堆疊資訊:
public class StackTraceUtil {
public static String getStackTrace(Throwable exception) {
if (exception != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
exception.printStackTrace(pw);
return sw.toString();
} else {
return "thrown exception is null.no more exception information can provide..";
}
}
Checking String equality using == or !=
通過==而不是equals比較字串資料。
程式碼示例
String a=”abc”
String b=”abc”;
System.out.println(a==b)
分析
“==”是比較指標是否指向同一地址,而equals比較的是資料。事實上除了原子型別的資料外,其它大部分情況下,值比較都應該使用equals。
String是個特殊情況。為了提高效率,JVM 維護了字串池。以上程式碼裡定義b時,b仍然指向a的指標,而不是重新分配一塊記憶體給b.所以雖然對於a==b來說,比較的是地址指標,但a==b仍然為true.但對於如下場景 a==b將為false:
String a= “abc”;
String b= new String(“abc”);
System.out.println (a==b).
在以上程式碼裡 new String重新為b分配了一塊記憶體,所以結果將是false.
修正
使用equals進行值比較
過載方法名寫錯
程式碼示例
public int hashcode(Object o){
return this.a.hashCode()+this.b.hashCode();
}
分析
以上程式碼本意應該是想過載Object的hashCode(Object o)方法。但不小心些錯了。對於jdk5及以後的jvm,可以通過@override在編譯期發現改問題。對於jdk1.4及以前的環境,只能通過小心檢查來避免這種情況。不過很多IDE工具都提供對這種常見需覆蓋方法(比如hashCode,equals等)的智慧化完成功能。
HTTP Response Splitting
對於XSS漏洞,通常情況下通過過濾轉換<,>等敏感字元來防禦。但對於http response splitting(報頭分離)漏洞,還應該針對回車、換行這兩個敏感字元進行過濾。
程式碼示例
response.addHeader("Content-Disposition", "attachment; filename="
+ fileName);
修正
如果fileName的來源不可靠,則需要過濾\13\10(回車、換行)字元
其它
其它包括一些粗心造成的程式碼問題。比如對Nuberm型別的資料進行如下比較:Numbera.equals(“”)等。
以上為本次hot、warn級別的程式碼分析總結,具體問題程式碼明細見fortify 分析結果檔案。
系統安全攻擊問題
詳見:http://download.csdn.net/detail/u011897392/9806386
具體問題請參見:http://blog.sina.com.cn/s/blog_62bcc50c0100g1vi.html