Tomcat 7 的七大新特性

weixin_34015860發表於2013-04-03

Tomcat的7引入了許多新功能,並對現有功能進行了增強。很多文章列出了Tomcat 7的新功能,但大多數並沒有詳細解釋它們,或指出它們的不足,或提供程式碼示例。本文將明確描述TOMCAT 7中七個最顯著的特徵和新增的功能,並對其作出評論,而不是僅僅列出新的功能。本文還提供了程式碼例子以方便你可以對其有更好的理解。 

  本文分為兩個部分,分別是”TOMCAT 7的新特性”和“TOMCAT 7增強的功能“。 

  TOMCAT 7新特性

  1 使用隨機數去防止跨站指令碼攻擊。 

  2 改變了安全認證中的jessionid的機制,防止session攻擊。 

  3 記憶體洩露的偵測和防止 

  4 在war檔案外使用別名去儲存靜態內容。 

  TOMCAT 7的增強功能 

  5 對Servlet 3.0,JSP 2.2和JSP-EL 2。2的支援 

  6 更容易將Tomcat內嵌到應用去中去,比如JBoss 

  7 非同步日誌記錄 

  根據Mark Thomas,Tomcat 7委員會的經理的說法,Tomcat 7最顯著的三個特徵是Servlet 3.0,記憶體檢測洩露和增強的安全特性。 

  Tomcat 7的例子程式中,包含了Eclipse的工程檔案和Ant的構建檔案,以方便去構建war檔案。其中Eclipse工程檔案有例子程式碼描述了Tomcat 7的一些新特性。 

  下面逐一開始介紹。 

  TOMCAT 7新特性 

1、使用隨機數去防止跨站請求偽造攻擊。 

  Wikipedia將跨站請求偽造攻擊(Cross Site Request forgery,CSRF)定義為:“一種影響Web應用的惡意攻擊。CSRF讓使用者當進入一個可信任的網頁時,被強行執行惡意程式碼。 

  經典的防止CSRF攻擊的方法是使用隨機數的方式,Wikipedia中定義為“利用隨機或偽隨機數嵌入到認證協議中,以確保舊的不能在以後的重放攻擊中被利用。” 

   Tomcat 7中有一個servlet過濾器,用於將隨機數儲存在使用者每次請求處理後的seesion會話中。這個隨機數,必須作為每次請求中的一個引數。 Servlet過濾器然後檢查在請求中的這個隨機數是否與儲存在使用者session中的隨機數是一樣的。如果它們是相同的,該請求是判斷來自指定的網站。 如果它們是不同的,該請求被認為是從其他網站發出並且會被拒絕。 

  這個servlet過濾器是十分簡單的,下面是從TOMCAT 原始碼CsrfPreventionFilter文件中摘錄的片段:

Java程式碼
  1. public   class  CsrfPreventionFilter  extends  FilterBase {   
  2.   
  3. public   void  doFilter(ServletRequest request, ServletResponse response,   
  4. FilterChain chain) throws IOException, ServletException {   
  5.   
  6. String previousNonce = req.getParameter(Constants.CSRF_NONCE_REQUEST_PARAM);   
  7. String expectedNonce = (String) req.getSession(true).getAttribute(Constants.CSRF_NONCE_SESSION_ATTR_NAME);   
  8.   
  9. if  (expectedNonce !=  null  && !expectedNonce.equals(previousNonce)) {   
  10. res.sendError(HttpServletResponse.SC_FORBIDDEN);   
  11. return ;   
  12. }   
  13.   
  14. String newNonce = generateNonce();   
  15. req.getSession(true).setAttribute(Constants.CSRF_NONCE_SESSION_ATTR_NAME, newNonce);   

 
  所以每個URL地址中都有一個從使用者session中提取的隨機數,下面是使用的JSTL例子: 

  在以前,JSTL中構造連結可以這樣: 

< c:url var="url" value="/show" > 
< c:param name="id" value="0" / > 
< /c:url > 
< a href="${show}" >Show< /a > 

  而現在可以這樣: 

< c:url var="url" value="/show" > 
< c:param name="id" value="0" / > 
< c:param name="org.apache.catalina.filters.CSRF_NONCE" value="${session.org.apache.catalina.filters.CSRF_NONCE}" / > 
< /c:url > 

  具體的例子可以參考TOMCAT 7自帶例子中的演示,這個過濾器可以在web.xml中進行配置,配置後,所有訪問如http://localhost:8080/tomcat7demo/csrf/ 的都必須帶上引數,不帶上引數的話會出現403禁止訪問錯誤。 

  當然這種方法的缺點就是所有的連結都必須帶上這個隨機數。


2、 改變了安全認證中的jessionid的機制,防止session攻擊。 

  Session劫持攻擊通常是以下的情況: 

  1 惡意攻擊者先訪問一個網頁,由於cookie是以jsession id的方式儲存在瀏覽器中的,即使攻擊者不登陸,他可以偽造一個帶有jsession id的地址,把它發給受害者,比如 

  http://example.com/login?JESSIONID=qwerty) 

  2 受害者點這個帶有jsessionid的連結,提示輸入驗證資訊之後就登陸系統。 

  3 攻擊者現在使用這個帶jsessionid的連結,以受害者的身份登陸進系統了。 

   對於攻擊者來說,將jsessionid加在url中以及通過一個惡意表單傳送出去是很容易的事,對於session劫持攻擊的更詳細描述,請參考 Acros Security組織的白皮書“Session Fixation Vulnerability in Web-based Applications”。 

  TOMCAT 7對此的解決方案是一個補丁,它在驗證後改變了jsessionid。這個補丁主要是應用在TOMCAT 7中,當然在TOMCAT 5和6中也可以使用但只是有些不同。 

  根據Mark Thomas說的,應用了Tomcat 7的這個補丁後: 

  • TOMCAT預設情況下安全性不再變得脆弱,因為驗證後會話發生了變化 

  • 如果使用者改變了預設設定(比如應用程式不能處理變化了的session id),風險也會降到最小,因為在Servlet 3中,可以禁止在url中進行會話跟蹤。 

  而在TOMCAT 5和TOMCAT 6中,應用了補丁後: 

  • 能阻止session劫持攻擊,因為能讓TOMCAT在驗證後改變session id。 

  • 如果應用程式不能處理變化了的session id,可以通過寫自定義的過濾器去檢查request.isRequestedSessionIdFromURL()和其返回的結果,以降低風險。 

  以上這些改變都是TOMCAT在幕後所做的,開發者根本不用去理會。 

3 、記憶體洩露的偵測和防止

  開發者在部署他們寫的程式到生產環境上時,經常會遇到Pemgen錯誤:OutOfMemoryError。這是由於記憶體洩露而引起的。通常開發者是通過增大permgen記憶體的大小去解決或者就是重新啟動tomcat。 

   TOMCAT 7包含了一個新的特性,它通過把不能垃圾回收的引用物件移走的方法,能解決一些Permgen記憶體洩露的問題。這個特性對程式設計師部署應用程式在他們的開發 環境中是十分方便的,因為程式設計師在開發環境中為了節省時間一般不重新啟動Tomcat就能部署新的war檔案。在生產環境中,最好的建議還是停掉 TOMCAT,然後清除work下面的目錄檔案並且重新部署應用。 

  當然,記憶體洩露檢測和防止這個特性現在還不是很完善,還是有的情況TOMCAT不能檢測記憶體洩露和修復之的,所以對於生產環境,最好的的辦法還是停掉TOMCAT,然後清除work下面的目錄檔案並且重新部署應用。 

  Mark Thomas解析應用程式或者庫程式在如下情況下會觸發記憶體洩露: 

  • JDBC驅動的註冊 

  • 一些日誌框架 

  • 在ThreadLocals中儲存了物件但沒有刪除它們 

  • 啟動了執行緒但沒停止 

  而 Java API 存在記憶體洩漏的地方包括: 

  1.使用 javax.imageio API ( Google Web Toolkit會用到) 

  2.使用 java.beans.Introspector.flushCaches() 

  3.使用 XML 解析器 

  4.使用 RMI 遠端方法呼叫 

  5.從 Jar 檔案中讀取資源


4、 在war檔案外使用別名去儲存靜態內容 

  Web應用程式需要靜態資原始檔, 比如象CSS,Javascript和視訊檔案、圖片檔案等。通常都把它們打包放在war檔案中,這將增加了WAR檔案的大小並且導致很多重複的載入靜態 資源。一個比較好的解決方法是使用Apache HTTP伺服器去管理這些靜態檔案資源,下面是一個apache httpd.conf檔案的配置摘錄: 

< Directory "/home/avneet/temp/static" > 
Order allow,deny 
Allow from all 
< /Directory > 
Alias /static "/home/avneet/temp/static" 

  以上的設定,使得訪問http://localhost/static時,能訪問到放在/home/avneet/temp/static下的資源。 

   允許使用新的aliases屬性,指出靜態檔案資源的位置,可以通過使用 Classloader.getResourceAsStream('/static/...')或者在連結中嵌入的方法讓TOMCAT去解析絕對路徑, 下面是一個在context.xml中配置的例子: 

< ?xml version="1.0" encoding="UTF-8"? > 
< Context path="/tomcat7demo" aliases="/static=/home/avneet/temp/static" > 
< /Context > 

  假設/home/avneet/temp/static這個資料夾存放有一張圖片bg.png,如果war檔案以tomcat7demo的名字部署,那麼可以通過以下三個方式去訪問這張圖片 

  1 直接訪問 

  http://localhost:8080/tomcat7demo/static/bg.png 

  2 在HTML連結中訪問:< img src="/tomcat7demo/static/bg.png" / > 

  3 通過JAVA程式碼訪問: ByteArrayInputStream bais = (ByteArrayInputStream)getServletContext().getResourceAsStream("/static/bg.png"); 

  使用aliases的好處是可以代替Apache的httpd.conf的設定,並且可以在servlet容器範圍內訪問,並且不需要Apache。 

  TOMCAT 7的增強特性 

5、對Servlet 3.0,JSP 2.2和JSP-EL 2。2的支援

  Servlet 3的增強特性有: 

  • 可以在POJO或者過濾器filters中使用annotations註釋(在web.xml中不再需要再進行設定了) 

   • 可以將web.xml分塊進行管理了。也就是說,使用者可以編寫多個xml檔案,而最終在web.xml中組裝它們,這將大大降低web.xml的複雜性增 強可讀性。比如, struts.jar和spring-mvc.jar每一個都可以有一個web-fragment.xml。開發者不再需要在web.xml中去配置它們 了,在web-fragment.xml中的jar檔案會自動載入,並且struts/spring-mvc servlets和filters也會自動裝配設定。 

  • 非同步處理web的請求----這個特性在tomcat 6 中已經有了,現在在tomcat 7中以Servlet 3標準規範化了,能讓使用非同步I/O的web應用程式可以移植到不同的web容器中。非同步處理使用非阻塞I/O,每次的HTTP連線都不需要對應一個線 程。更少的執行緒可以為更多的連線提供服務。這對於需要長時間計算處理才能返回結果的情景來說是很有用的,比如產生報表,Web Servce呼叫等。 

  • 安全的增強---Servlet 3.0現在使用SSL 去加強了會話session的跟蹤,代替了原來的cookie和URL重寫。


6 、更容易將Tomcat內嵌到應用去中去 

  Tomcat 7現在可以嵌入到應用程式中去,並可以通過程式去動態設定和啟動。象在CATALINA_HOME/conf/server.xml中的很多配置,現在都 可以用程式動態去設定了。在Tomcat 7前,Tomcat 6提供了一個嵌入類,它能方便地去配置Tomcat。但在TOMCAT 7中,這個類已被廢棄了。這個新的Tomcat 7的類,使用了幾個預設的配置元素,並提供了一個更容易和簡單的方法去嵌入Tomcat。 

  下面是CATALINA_HOME/conf/server.xml中的一些相關屬性和配置: 

< Server > 
< Service > 
< Connector port="8080 > 
< Engine > 
< Host appBase="/home/avneet/work/tomcat7demo/dist" / > 
< /Engine > 
< /Connector > 
< /Service > 
< /Server > 

  我們可以通過程式去進行動態設定了: 

final String CATALINA_HOME = "/home/avneet/work/temp/tomcat7demo/"; 
Tomcat tomcat = new Tomcat(); 
tomcat.setBaseDir( CATALINA_HOME ); 
tomcat.setPort( 8080 ); 
tomcat.addWebapp("/tomcat7demo", CATALINA_HOME + "/webapps/tomcat7demo.war"); 
tomcat.start(); 
System.out.println("Started tomcat"); 
tomcat.getServer().await(); //Keeps Tomcat running until it is shut down 
//Webapp tomcat7demo accessible at http://localhost:8080/tomcat7demo/ 

7 、非同步日誌記錄 

   TOMCAT 7現在包括了一個非同步日誌記錄器(AsyncFileHandler)。AsyncFileHandler繼承了FileHandler類並能代替 FileHandler。使用AsyncFileHandler,時,只需要在CATALINA_HOME/conf /logging.properties中把FileHandler全部替換為AsyncFileHandler就可以了。要注意的是非同步日誌不能跟 log4一起工作。 

  當有日誌發向AsyncFileHandler時,日誌被加入到佇列中 (java.util.concurrent.LinkedBlockingDeque)並且方法呼叫的資訊會馬上返回不需要等待I/O寫到磁碟中。當類 載入器載入AsyncFileHandler時,會有一個單獨的執行緒啟動,這個執行緒會從佇列中讀取日誌資訊並且寫到磁碟中去 

  這種方法的好處是如果I/O速度很慢(比如日誌要儲存在遠端的裝置上)時,記錄日誌的請求和處理過程不會顯得很慢。 

  AsyncFileHandler使用生產者和消費者的關係原理,在佇列中儲存日誌資訊。佇列預設大小為10000。為了預防佇列溢位,預設是丟棄最後的資訊。預設的佇列大小和溢位的設定都可以通過啟動引數進行設定。 

  關於TOMCAT 7的示例程式 

  TOMCAT 7的自帶程式例子有兩個servlets,一個是演示瞭如何採用隨機數的辦法防止CSRF攻擊,另外一個是描述了使用aliases。更新一下web/META-INF/context.xml,指出圖片的絕對路徑即可順利執行。 

  通過ant執行build.xml去將它們部署到tomcat 7中,使用如下兩個地址訪問: 

  • http://localhost:8080/tomcat7demo/csrf/ 

  • http://localhost:8080/tomcat7demo/alias/

 

轉自:http://www.blogjava.net/libin2722/articles/333424.html

相關文章