1. 程式人生 > >javax.servlet.http.Cookie.setHttpOnly(Z)V

javax.servlet.http.Cookie.setHttpOnly(Z)V

java.lang.NoSuchMethodError: javax.servlet.http.Cookie.setHttpOnly(Z)V
使用tomcat6 轉換為7  即可

在Servlet 3.0中增加對Cookie(請注意,這裡所說的Cookie,僅指和Session互動的Cookie,即人們常說的會話Cookie)較為全面的操作API。最為突出特性:支援直接修改Session ID的名稱(預設為“JSESSIONID”),支援對cookie設定HttpOnly屬性以增強安全,避免一定程度的跨站攻擊。


利用攔截器實現,判斷每次請求的響應是否包含SET-COOKIE頭部,重寫會話Cookie,新增需要的屬性。雖較為生硬,但靈活性強。


新的規範API
新的規範新增SessionCookieConfig介面,用於操作會話Cookie,需要掌握以下主要方法:

    setName(String name)
    修改Session ID的名稱,預設為"JSESSIONID"
    setDomain(String domain)
    設定當前Cookie所處於的域
    setPath(String path)
    設定當前Cookie所處於的相對路徑

    setHttpOnly(boolean httpOnly)
    設定是否支援HttpOnly屬性
    setSecure(boolean secure)
    若使用HTTPS安全連線,則需要設定其屬性為true
    setMaxAge(int maxAge)
    設定存活時間,單位為秒

如何使用呢,很方便,在ServletContextListener監聽器初始化方法中進行設定即可;下面例項演示如何修改"JSESSIONID",以及新增支援HttpOnly支援:


/** 全域性設定Session-Cookie相互動部分屬性

* @author yongboy
* @date 2011-1-19
* @version 1.0
*/
@WebListener
public class SessionCookieInitialization implements ServletContextListener {
private static final Log log = LogFactory
   .getLog(SessionCookieInitialization.class);

public void contextInitialized(ServletContextEvent sce) {
  log.info("now init the Session Cookie");

  ServletContext servletContext = sce.getServletContext();

  SessionCookieConfig sessionCookie = servletContext
    .getSessionCookieConfig();
  sessionCookie.setName("YONGBOYID");
  sessionCookie.setPath(servletContext.getContextPath());
  sessionCookie.setHttpOnly(true);
  sessionCookie.setSecure(false);

  log.info("name : " + sessionCookie.getName() + "\n" + "domain:"
    + sessionCookie.getDomain() + "\npath:"
    + sessionCookie.getPath() + "\nage:"
    + sessionCookie.getMaxAge());

  log.info("isHttpOnly : " + sessionCookie.isHttpOnly());
  log.info("isSecure : " + sessionCookie.isSecure());
}

public void contextDestroyed(ServletContextEvent sce) {
  log.info("the context is destroyed !");
}
}

需要通過ServletContext物件獲得SessionCookieConfig物件,才能夠進一步自定義session cookie的名字等屬性。
無論以前的硬編碼還是新的API實現,目標都是一致的,所產生頭部資訊也是完全一致。毫無疑問,後者更為方便快捷,省缺了顯示的操作響應元資料。
對當前站點的第一次請求,很容易從響應頭資訊中看到Set-Cookie的屬性值:

image


不同瀏覽器平臺上測試

    在Safari、IE8、Opera 11 一切都很正常
    Firefox 3.6、Chrome 9.0,JSESSIONID會繼續存在:

        YONGBOYID=601A6C82D535343163B175A4FD5376EA; JSESSIONID=AA78738AB1EAD1F9C649F705EC64D92D; AJSTAT_ok_times=6; JSESSIONID=abcpxyJmIpBVz6WHVo_1s; BAYEUX_BROWSER=439-1vyje1gmqt8y8giva7pqsu1

    在所有瀏覽器中,SESSION ID等於新設定的YONGBOYID值(若不相等,問題就嚴重了!)
    在客戶端JS無法獲得正確的SESSIONI ID了。

Tomcat伺服器內建支援

在Tomcat 6-7,可以不用如上顯示設定Cookie domain、name、HttpOnly支援,在conf/context.xml檔案中配置即可:

    <Context useHttpOnly="true", sessionCookieName="YONGBOYID", sessionCookieDomain="/servlet3" … >
    ...
    </Context>

既然JAVA應用伺服器本身支援會話Cookie設定,那就沒有必要在程式程式碼中再次進行編碼了。這是一個好的實踐:不要重複造輪子。
這裡給出一段測試Session重寫的一段指令碼:

<div style="margin: 40px; paddding: 10px">
<div><a href="sessionCookieTest">正常連線</a></div>
<div><a href="<%=response.encodeURL("sessionCookieTest") %>">重定向連線</a></div>
</div>

會被重寫的URL地址類似於:

    http://localhost/servlet3/sessionCookieTest;YONGBOYID=19B94935D50245270060E49C9E69F5B6 

嗯,在取消會話Cookie之後,可以直接看到修改後的SESSION ID名稱了,當然這時候HttpOnly屬性也沒有多大意義了。
有一點別忘記,設定HttpOnly之後,客戶端的JS將無法獲取的到會話ID了。
進階閱讀:

    維基對HttpOnly的解釋
    利用HTTP-only Cookie緩解XSS之痛
    Tomcat Context 屬性
    HttpOnly cookie與跨站點追蹤