Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Session issues with Spring #47

Closed
michael-kalpana opened this issue Apr 4, 2017 · 12 comments · Fixed by #52
Closed

Session issues with Spring #47

michael-kalpana opened this issue Apr 4, 2017 · 12 comments · Fixed by #52
Assignees
Labels

Comments

@michael-kalpana
Copy link

michael-kalpana commented Apr 4, 2017

Hazelcast WM 3.7.1

We have discovered two issues when using Hazelcast wm with Spring.

1. Session fixation vulnerability

Say you visit the login page of a server. After this initial request two cookies are provided: the JSession ID (or 'Tomcat Session ID' as it is referred to in my patch) and the Hazelcast session ID. If the JSession ID is then modified (to be made incorrect) or removed from the client and then you authenticate with the server when the original Hazelcast session will not be destroyed.

2. Stale cached hazelcast session issue

Say you have two server nodes behind a load balancer. Prior to authentication you have a request handled by both nodes so that each one has the initial hazelcast session ID cached locally against a JSession ID. Say node '1' performs the authentication of a login request. When a request is next sent to node '2' it will attempt to use the locally cached hazelcast session ID which was mapped to the JSession ID to the initial request to node '2'. The observed effect of this is that the request to node '2' will fail as it is not authenticated.

I have provided a patch to the SpringAwareWebFilterTest for the two scenarios above.

SpringAwareWebFilterTest.java.patch.zip

@emre-aydin
Copy link
Contributor

Hi @michael-kalpana

Thanks for the detailed explanation, especially for the patch with tests. I have created a PR for solving the issue. It will probably be released next week. Meanwhile you can bring the changes in to your local copy and try them. You can update the issue if the fix does not work for you.

@emre-aydin emre-aydin added the bug label Apr 12, 2017
@michael-kalpana
Copy link
Author

michael-kalpana commented Apr 12, 2017

Hi,

Thanks for addressing this so quickly.

I'm testing with your fix but I seem to get a null pointer when I'm unauthenticated.

Here's a snippet of the stack trace:

java.lang.NullPointerException: null
	at com.hazelcast.web.WebFilter$HazelcastRequestWrapper.isRequestedSessionIdValid(WebFilter.java:369) ~[hazelcast-wm-3.8.1-SNAPSHOT.jar:3.8.1-SNAPSHOT]
	at javax.servlet.http.HttpServletRequestWrapper.isRequestedSessionIdValid(HttpServletRequestWrapper.java:247) ~[servlet-api.jar:na]
	at javax.servlet.http.HttpServletRequestWrapper.isRequestedSessionIdValid(HttpServletRequestWrapper.java:247) ~[servlet-api.jar:na]
	at javax.servlet.http.HttpServletRequestWrapper.isRequestedSessionIdValid(HttpServletRequestWrapper.java:247) ~[servlet-api.jar:na]
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:90) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106) ~[spring-web-3.2.18.RELEASE.jar:3.2.18.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]

@emre-aydin
Copy link
Contributor

@michael-kalpana I have updated the PR. That should solve the problem.

@michael-kalpana
Copy link
Author

Hi @emre-aydin ,

I seem to have another issue:

  1. Log in as a user
  2. Log out as a user
  3. Attempt to access a resource that requires authentication. Get re-directed to login page.
  4. Log in as user. Next call to server from client will not be authenticated.

Please let me know if you have any trouble re-creating this.

@emre-aydin
Copy link
Contributor

Hey @michael-kalpana

A reproducer would be really helpful.

@michael-kalpana
Copy link
Author

Hi,

Please see patch attached for re-creation.

Thanks.

forward-bug-patch.zip

@michael-kalpana
Copy link
Author

Hi @emre-aydin ,

How are things going with last issue I reported? Do you need any further info?

Thanks.

@emre-aydin
Copy link
Contributor

Hi @michael-kalpana

I didn't have time to look at the issue again.

@michael-kalpana
Copy link
Author

@emre-aydin

No worries, but can you give a possible estimate for delivery? Without this fix we won't be able to upgrade our Hazelcast version.

@emre-aydin
Copy link
Contributor

emre-aydin commented May 5, 2017

Following lines in SpringAwareWebFilterTest do not behave as expected in your patch, please fix it:

        // Make a requests to a secured API and get redirected to the login screen
        HttpResponse response = request("api/forward", this.serverPort1, sss.cookieStore);
        Header locationHeader = response.getFirstHeader("Location");
        Assert.assertTrue(locationHeader.getValue().contains("spring_security_login"));
        Assert.assertEquals(302, response.getStatusLine().getStatusCode());

locationHeader is null, so test gets NPE before having a chance to test anything. I have applied the patch on my PR's branch. I assume you did the same? Am I missing something?

@michael-kalpana
Copy link
Author

michael-kalpana commented May 5, 2017

I see what's happened. I was pointing to JDK 7 when I wrote it - I just ran it using JDK 8 and got the same issue as you.

If you run using JDK 7 for now you should be able to see the scenario.

EDIT: Just did some reading, seems that Spring 3.X which you are using does not support JDK 8.

@emre-aydin
Copy link
Contributor

Hi @michael-kalpana

I had another look into your issue. Here's what happens:

  1. Spring MVC forwards the request when you return "forward:/api/createSession" from your controller's request handler method - by using javax.servlet.RequestDispatcher#forward
  2. Tomcat's javax.servlet.RequestDispatcher implementation org.apache.catalina.core.ApplicationDispatcher wraps the request in an org.apache.catalina.core.ApplicationHttpRequest instance in its doForward method.
  3. ApplicationHttpRequest implements getSession() method and has no knowledge about the Hazelcast session. When getSession() is called on the request, it doesn't get the session from Hazelcast.

I don't think there's an easy solution. I have tried with different Tomcat versions but they all implement javax.servlet.RequestDispatcher#forward in a similar manner. You can try with other servlet containers such as Jetty but they might have a similar implementation of it as well. So at this point, I will merge the solution to your original issue and close the issue when I merge it. For the forwarding problem, I have created another issue. You can subscribe to it for following the progress and contribute any ideas/solutions you might have: #57

emre-aydin added a commit that referenced this issue Jul 25, 2017
Two problems solved:

- Fix session fixation vulnerability
- Fix stale Hazelcast session issue

Session fixation vulnerability occurred with Spring Security MVC
 as it used isRequestedSessionIdValid method on HttpServletRequest
 interface which was not implemented before this commit.

Stale Hazelcast session issue occurs when a request comes in with a
 valid JSESSIONID and a hazelcast.sessionId that corresponds to
 another Hazelcast session. In this case, we just used the existing
 session and used the incoming JSESSIONID to find the corresponding
 hazelcast.sessionId and Hazelcast session. Now we let the incoming
 hazelcast.sessionId to override the hazelcast.sessionId that
 corresponds to the request's JSESSIONID.

Fix #47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants