jsessionid是Java Web Server(即Servlet/JSP Server)中为了防止客户端屏蔽cookie而在URL中放置的sessionid的统称。支持Servlet标准的Web容器,例如Tomcat,都支持以URL重写的方式在URL中加入jsessionid。目前在大量的网站中都有用到,但是其存在的一些问题被越来越多的人认为是有害的,并且建议不适用jsessionid。
使用jsessionid存在问题主要有一下几点:
- Every link on your site needs manual intervention
Cookieless sessions are achieved in Java by appending a string of the format ;jsessionid=SESSION_IDENTIFIER to the end of a URL. To do this, all links emitted by your website need to be passed through either HttpServletRequest.encodeURL(), either directly or through mechanisms such as the JSTL <c:out /> tag. Failure to do this for even a single link can result in your users losing their session forever.
- Using URL-encoded sessions can damage your search engine placement
To prevent abuse, search engines such as Google associate web content with a single URL, and penalize sites which have identical content reachable from multiple, unique URLs. Because a URL-encoded session is unique per visit, multiple visits by the same search engine bot will return identical content with different URLs. This is not an uncommon problem; a test search for ;jsessionid in URLs returned around 79 million search results.
- It's a security risk
Because the session identifier is included in the URL, an attacker could potentially impersonate a victim by getting the victim to follow a session-encoded URL to your site. If the victim logs in, the attacker is logged in as well - exposing any personal or confidential information the victim has access to. This can be mitigated somewhat by using short timeouts on sessions, but that tends to annoy legitimate users.
既然存在上面的问题,我们就会想到让web容器禁用URL重写功能。不幸的是,Servlet规范并没有定义一个标准的方法来禁用URL重写jsessionid,导致很多web容器本身就不提供禁用URL重写jsessionid的方法。
The solution is to create a servlet filter which will intercept calls to HttpServletRequest.encodeURL() and skip the generation of session identifiers. This will require a servlet engine that implements the Servlet API version 2.3 or later (J2EE 1.3 for you enterprise folks). Let's start with a basic servlet filter:
package com.randomcoder.security;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
public class DisableUrlSessionFilter implements Filter
{
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException
{
// TODO add filter logic here
}
public void init(FilterConfig config)
throws ServletException {}
public void destroy() {}
}
We don't need to be concerned with the init() and destroy() methods; let's focus on doFilter(). First, let's exit quickly if for some reason the current request is non-HTTP, and cast the request and response objects to their HTTP-specific equivalents:
if (!(request instanceof HttpServletRequest))
{
chain.doFilter(request, response);
return;
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
Next, let's invalidate any sessions that are backed by a URL-encoded session id. This prevents an attacker from generating a valid link. Just because we won't be generating session-encoded links doesn't mean someone else won't try:
if (httpRequest.isRequestedSessionIdFromURL())
{
HttpSession session = httpRequest.getSession();
if (session != null) session.invalidate();
}
To disable the default URL-encoding functionality, we need to wrap the existing HttpServletResponse object. Fortunately, the Servlet API provides just such a class ready-made in HttpServletResponseWrapper. We could subclass it to provide our own handling, but this is a trivial enough change that an anonymous inner class will do nicely:
HttpServletResponseWrapper wrappedResponse
= new HttpServletResponseWrapper(httpResponse)
{
public String encodeRedirectUrl(String url) { return url; }
public String encodeRedirectURL(String url) { return url; }
public String encodeUrl(String url) { return url; }
public String encodeURL(String url) { return url; }
};
You may notice that we have overridden four methods, not one. encodeRedirectURL is used to encode redirected URLs, which can sometimes require different logic to determine if session identifiers are required. The other two methods are deprecated, but are included here for completeness.
Finally, we need to pass the original request and our response wrapper to the next filter in the chain:
chain.doFilter(request, wrappedResponse);
Our servlet filter is now written, but we still need to tell our servlet container about it. For this, we need to add the following to web.xml:
<filter>
<filter-name>
DisableUrlSessionFilter
</filter-name>
<filter-class>
com.randomcoder.security.DisableUrlSessionFilter
</filter-class>
</filter>
...
<filter-mapping>
<filter-name>DisableUrlSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This registers our filter with the servlet container, and maps it to all requests. For best results, the filter mapping should be placed above any other filter mappings to prevent any calls to encodeURL from slipping through.
代码见附件
Update: http://boncey.org/2007_1_8_purging_jsessionid This site offers some additional advice using mod_rewrite.
原文:
http://randomcoder.com/articles/jsessionid-considered-harmful
Improved Session Tracking:
http://www.mojavelinux.com/blog/archives/2006/09/improved_session_tracking/