聂永的博客

记录工作/学习的点点滴滴。

Servlet 3.0笔记之会话Cookie设置相关

在Servlet 3.0中增加对Cookie(请注意,这里所说的Cookie,仅指和Session互动的Cookie,即人们常说的会话Cookie)较为全面的操作API。最为突出特性:支持直接修改Session ID的名称(默认为“JSESSIONID”),支持对cookie设置HttpOnly属性以增强安全,避免一定程度的跨站攻击。
相关较为深入信息,请访问进阶阅读部分。
以前的实现
虽然新的API提供了简答便捷的API操作会话Cookie,但新的API之前,我们可以较为生硬的操作响应头部,完成设定工作。看看以前的代码吧:
/**
* 自定义会话Cookie属性
* @author yongboy
* @date 2011-1-19
* @version 1.0
*/
@WebFilter(dispatcherTypes = { DispatcherType.REQUEST }, urlPatterns = { "/*" })
public class CustomCookieFilter implements Filter {
private static final Log log = LogFactory.getLog(CustomCookieFilter.class);
private static final String CUSTOM_SESSION_ID = "YONGBOYID";
private static final String HTTP_ONLY = "HttpOnly";
private static final String SET_COOKIE = "SET-COOKIE";

public void destroy() {
}

public void doFilter(ServletRequest req, ServletResponse rep,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) rep;

if (response.containsHeader(SET_COOKIE)) {
log.info("haha,we have one new user visit the site ...");

String sessionId = request.getSession().getId();
String cookieValue = CUSTOM_SESSION_ID + "=" + sessionId + ";Path="
+ request.getContextPath() + ";" + HTTP_ONLY;

log.info(SET_COOKIE + ":" + cookieValue);

response.setHeader(SET_COOKIE, cookieValue);
}

chain.doFilter(req, response);
}

public void init(FilterConfig fConfig) throws ServletException {
}
}

利用拦截器实现,判断每次请求的响应是否包含SET-COOKIE头部,重写会话Cookie,添加需要的属性。虽较为生硬,但灵活性强。

新的规范API

新的规范添加SessionCookieConfig接口,用于操作会话Cookie,需要掌握以下主要方法:
  1. setName(String name)
    修改Session ID的名称,默认为"JSESSIONID"
  2. setDomain(String domain)
    设置当前Cookie所处于的域
  3. setPath(String path)
    设置当前Cookie所处于的相对路径
  4. setHttpOnly(boolean httpOnly)
    设置是否支持HttpOnly属性
  5. setSecure(boolean secure)
    若使用HTTPS安全连接,则需要设置其属性为true
  6. 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


不同浏览器平台上测试

  1. 在Safari、IE8、Opera 11 一切都很正常
  2. Firefox 3.6、Chrome 9.0,JSESSIONID会继续存在:
    YONGBOYID=601A6C82D535343163B175A4FD5376EA; JSESSIONID=AA78738AB1EAD1F9C649F705EC64D92D; AJSTAT_ok_times=6; JSESSIONID=abcpxyJmIpBVz6WHVo_1s; BAYEUX_BROWSER=439-1vyje1gmqt8y8giva7pqsu1
  3. 在所有浏览器中,SESSION ID等于新设置的YONGBOYID值(若不相等,问题就严重了!)
  4. 在客户端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了。

进阶阅读:

  1. 维基对HttpOnly的解释
  2. 利用HTTP-only Cookie缓解XSS之痛
  3. Tomcat Context 属性
  4. HttpOnly cookie与跨站点追踪

posted on 2011-01-19 21:58 nieyong 阅读(7827) 评论(0)  编辑  收藏 所属分类: Servlet3


只有注册用户登录后才能发表评论。


网站导航:
 

公告

所有文章皆为原创,若转载请标明出处,谢谢~

新浪微博,欢迎关注:

导航

<2011年1月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

统计

常用链接

留言簿(58)

随笔分类(130)

随笔档案(151)

个人收藏

最新随笔

搜索

最新评论

阅读排行榜

评论排行榜