benlucchesi / grails-cookie-session

cookie sessions for grails applications
28 stars 32 forks source link

Serialized session exceeds maximum session size that can be stored in cookies. Max size: 8000, Requested Session Size: 11008. #59

Open priyanka83 opened 9 years ago

priyanka83 commented 9 years ago

We are using cookie session plugin in our application with spring security enabled . Seems like there is some unwanted data being stored in session which is causing the session size to increase dramatically. I have tried all of the above suggestions, bumping the number of cookies to 4 and increasing the header size and cookie session timeout. When increasing the number of cookies to 4 , it is having some issues when we try to logout /login. The exception we see is : ERROR cookiesession.CookieSessionRepository - cause: null java.lang.RuntimeException: = character not at end of base64 value.

Also we are seeing exceptions when it tries to deserialize the session and throws some gzip related to exceptions

This is the setting we have on config groovy:

grails.plugin.cookiesession.enabled = true grails.plugin.cookiesession.encryptcookie = true grails.plugin.cookiesession.cryptoalgorithm = "AES" grails.plugin.cookiesession.secret = cookieSecret grails.plugin.cookiesession.cookiecount = 1 grails.plugin.cookiesession.maxcookiesize = 8000 grails.plugin.cookiesession.sessiontimeout = 3600 grails.plugin.cookiesession.cookiename = 'gsession' grails.plugin.cookiesession.condenseexceptions = true grails.plugin.cookiesession.springsecuritycompatibility = true

Any help will be appreciated as this is causing too much havoc on our producion environment. The application is hosted on jboss 6.1 EAP.

benlucchesi commented 9 years ago

1) have you upgraded to latest version 2) does the problem start happening after fail logins and redirects?

On Tue, Jun 30, 2015, 2:14 PM priyanka83 notifications@github.com wrote:

We are using cookie session plugin in our application with spring security enabled . Seems like there is some unwanted data being stored in session which is causing the session size to increase dramatically. I have tried all of the above suggestions, bumping the number of cookies to 4 and increasing the header size and cookie session timeout. When increasing the number of cookies to 4 , it is having some issues when we try to logout /login. The exception we see is : ERROR cookiesession.CookieSessionRepository - cause: null java.lang.RuntimeException: = character not at end of base64 value.

Also we are seeing exceptions when it tries to deserialize the session and throws some gzip related to exceptions

This is the setting we have on config groovy:

grails.plugin.cookiesession.enabled = true grails.plugin.cookiesession.encryptcookie = true grails.plugin.cookiesession.cryptoalgorithm = "AES" grails.plugin.cookiesession.secret = cookieSecret grails.plugin.cookiesession.cookiecount = 1 grails.plugin.cookiesession.maxcookiesize = 8000 grails.plugin.cookiesession.sessiontimeout = 3600 grails.plugin.cookiesession.cookiename = 'gsession' grails.plugin.cookiesession.condenseexceptions = true grails.plugin.cookiesession.springsecuritycompatibility = true

Any help will be appreciated as this is causing too much havoc on our producion environment. The application is hosted on jboss 6.1 EAP.

— Reply to this email directly or view it on GitHub https://github.com/benlucchesi/grails-cookie-session-v2/issues/59.

priyanka83 commented 9 years ago

@benlucchesi : We have upgraded the cookie session plugin to the latest version and testing it out at present. The problem was intermittent and usually happening after redirects. We dint see any failed login attempts on the production logs. Will keep you posted. Thanks for the prompt response.

benlucchesi commented 9 years ago

If spring security is redirecting from a controller action due to lack of permission, spring security stuffs a copy of the request including a copy of the session. this is what causes it to explode in size. The latest version of the plugin removes the session the saved request to prevent this behavior.

On Wed, Jul 1, 2015, 12:19 PM priyanka83 notifications@github.com wrote:

@benlucchesi https://github.com/benlucchesi : We have upgraded the cookie session plugin to the latest version and testing it out at present. The problem was intermittent and usually happening after redirects. We dint see any failed login attempts on the production logs. Will keep you posted. Thanks for the prompt response.

— Reply to this email directly or view it on GitHub https://github.com/benlucchesi/grails-cookie-session-v2/issues/59#issuecomment-117799465 .

priyanka83 commented 9 years ago

@benlucchesi : we upgraded the plugin version and deployed to our production environment and we are not seeing any serialized session increase exceptions. Thank you very much for your help! :)

denis111 commented 8 years ago

For me the problem is still persists. I see that cookies are deleted from SPRING_SECURITY_SAVED_REQUEST but then after the session gets serialized to bytes by kryo that bytes still contain gsession things!! It's easy to proove. Put a breakpoint at the end of serialize method of KryoSessionSerializer. And evaluate such expression in your ide:

new File('session.txt').withOutputStream { it.write bytes }

Then open session.txt with text editor and you'll see all the cookies there. That's very strange because when you deserialize it there's no gsession cookies. I don't know how it's possible.

benlucchesi commented 8 years ago

That is very strange. To start with, what version of grails, spring security plugin, and cookie session are you using?

On Wed, Sep 2, 2015 at 7:30 AM, denis111 notifications@github.com wrote:

For me the problem is still persists. I see that cookies are deleted from SPRING_SECURITY_SAVED_REQUEST but then after the session gets serialized to bytes by kryo that bytes still contain gsession things!! It's easy to proove. Put a breakpoint at the end of serialize method of KryoSessionSerializer. And evaluate such expression in your ide:

new File('session.txt').withOutputStream { it.write bytes }

Then open session.txt with text editor and you'll see all the cookies there. That's very strange because when you deserialize it there's no gsession cookies. I don't know how it's possible.

— Reply to this email directly or view it on GitHub https://github.com/benlucchesi/grails-cookie-session-v2/issues/59#issuecomment-137103070 .

denis111 commented 8 years ago

Grails 2.5.1 , spring-security-core:2.0-RC5, cookie-session:2.0.18. I don't know how it's possible, maybe java bug or kryo or spring. java oracle jdk build 1.7.0_79-b15

Saved session in txt looks like:

ava.util.HashMaSPRING_SECURITY_CONTEX‘org.springframework.security.core.context.SecurityContextImpÏorg.codehaus.groovy.grails.FLASH_SCOP≈ java.util.concurrent.ConcurrentHashMaSPRING_SECURITY_SAVEDREQUES‘¬org.springframework.security.web.savedrequest.DefaultSavedRequest/immogeÔjava.util.ArrayLisÙorg.springframework.security.web.savedrequest.SavedCookiÂwasHerÂÇ1userI‰bb80e016-7836-3124-8cca-a8fa8120933Âjava.util.TreeMajava.lang.String$CaseInsensitiveComparatoÚaccepÙtext/html,application/xhtml+xml,application/xml;q=0.9,/_;q=0.∏accept-encodinÁgzip, deflatÂaccept-languagÂes-ES,es;q=0.8,en-US;q=0.5,en;q=0.≥cache-controÏmax-age=∞connectioÓkeep-alivÂcookiÂÒnwasHere=1; userId=bb80e016-7836-3124-8cca-a8fa8120933e; gsession-0=CK6zIAEXnf885hnozwUlZav5J/alofXZv5c6B/I8JY99YzMuZFnXPOXPFz56+zSfcyoLQlsY61K5tNvIKcB3YPcNS1rSi6Bi0Fwf4jnH4w7xTR0FTQVBulcaWKPoJyU5Pspyfzs1/N1cokbjWcL2aDxEmBObWfKsBRMSXUg2OEuT2PJdegMFwaK3kcdJ7jQzaHarvh9N00n0SiNs6kBsYvg9kxmwNNJz8BMx97ClcY7PmdBZ/In4Iyxy0aRvLXFZkT6dY9JpuCKVt/O90GU4Q3kWJ9NrJMW89iRGbW72uFn1utUwYAKz2d8LtveT5hrBLvtCxfH3DqKFJmkIOv0t6Vho7/0Mq/ko/lf/YYoADdQuZ27lTCRFDw8QIbnDLyo0ZPAvlVxivpkMkVi8XP3vR/YIZnTsMqoIVBqgjM51p9HcLBQhrvy7OYDaerBIOWzuB/..... and so on.

benlucchesi commented 8 years ago

hey denis111,

I don't see how this can be a bug in the serializer - its not going to manufacture cookies in the saved request in the session.

I don't know what actions are being performed in your app prior to the session being serialized, but could put a breakpoint the src/groovy/com/granicus/grails/plugins/cookiesession/SecurityContextSessionPersistenceListener.groovy and verify the session.SPRING_SECURITY_SAVED_REQUEST.cookies collection is being iterated over and that cookies are being removed. after everything is removed, can you then inspect the session.SPRING_SECURITY_SAVED_REQUEST in your debugger and verify nothing is left over.

Also, can you try clearing all cookies from your browser or use an incognito mode so that you get a fresh session and then try to repro the error. It could be that your browser is sending up a bad session that always results in a redirect. If you clear cookies and you aren't able to recreate, then its likely that bad cookies were stuck in the browser.

also, can you post your cookie session config settings (don't include your cookie session encryption key)

If you have any other details about the scenario, that would help too - redirects, etc.

denis111 commented 8 years ago

I started th browser in private mode. And tried to access a protected controller (/admin) few times to provoke redirects to login screen to see how saved session grows, here's the screenshot gsession

And here's my config: grails.plugin.cookiesession.enabled = true grails.plugin.cookiesession.encryptcookie = true grails.plugin.cookiesession.cryptoalgorithm = 'Blowfish/CBC/PKCS5Padding' grails.plugin.cookiesession.secret = 'noooooo' grails.plugin.cookiesession.serializer = 'kryo' grails.plugin.cookiesession.springsecuritycompatibility = true grails.plugin.cookiesession.cookiecount = 10

kys30 commented 8 years ago

Hi benlucchesi ,

We are also facing a similar issue with our application.

We are using Grails 2.3.2 with Spring security - 2.0RC2 and Cookiesession 2.0.16.

  1. With java serializer, the cookie size increases very rapidly with every failed login attempt.
  2. Also, we are not getting redirected to the correct url after signing in (it gets redirected to the default URL). I think this problem is arising due to SPRING_SECURITY_SAVED_REQUEST. Just to keep the size in check, I tried to flush out session.SPRING_SECURITY_SAVED_REQUEST after in login/auth. In this case, I am able to restrict the cookie size (1033Kb, which is also a bit high) but again, loose all the saved request information.
  3. Using kryo serializer is decreasing the cookie size but it gives a lot of intermittent authentication issues.

Do we have any work around over this.

Thanks, Kaushik

benlucchesi commented 8 years ago

Kaushik,

thanks for the feed back on this. I've gotten a couple of reports regarding session sizes increasing even though the SPRING_SECURITY_SAVED_REQUEST is getting cleared out.

I've just finished upgrading the plugin to grails 3.0 and I've got a working branch with upgrades kryo to latest version. As I work through issues with that branch, I'll see if I can get to the root cause of this.

-ben

On Mon, Sep 28, 2015 at 9:54 AM, Kaushik Shelat notifications@github.com wrote:

Hi benlucchesi ,

We are also facing a similar issue with our application.

We are using Grails 2.3.2 with Spring security - 2.0RC2 and Cookiesession 2.0.16.

1.

With java serializer, the cookie size increases very rapidly with every failed login attempt. 2.

Also, we are not getting redirected to the correct url after signing in (it gets redirected to the default URL). I think this problem is arising due to SPRING_SECURITY_SAVED_REQUEST. Just to keep the size in check, I tried to flush out session.SPRING_SECURITY_SAVED_REQUEST after in login/auth. In this case, I am able to restrict the cookie size (1033Kb, which is also a bit high) but again, loose all the saved request information. 3.

Using kryo serializer is decreasing the cookie size but it gives a lot of intermittent authentication issues.

Do we have any work around over this.

Thanks, Kaushik

— Reply to this email directly or view it on GitHub https://github.com/benlucchesi/grails-cookie-session/issues/59#issuecomment-143803329 .

benlucchesi commented 8 years ago

Guys, I've been trying to repro the issue by failing log in attempts and I can't get the session to explode.

Try something for me though.... add this setting and test out your scenario:

grails.plugin.cookiesession.condenseexceptions = true

exceptions are notoriously unhealthy for serializers and cookie-sessions. If an exception gets stuffed into the session, it ends up taking a ton of data into the session, possibly including references to the request which contained the cookie. If this happened, it would explain why cookies keep reappearing in the session even though the saved request gets cleared out.

Please try this and let me know how it works.

-ben

denis111 commented 8 years ago

Should the same config option work for 2.0.18? (seems not or just not solves the problem)

benlucchesi commented 8 years ago

the condenseexceptions option does work for 2.0.18, however, I was finally able to repro the issue and condenseexceptions didn't help. I'm working on root cause now...

benlucchesi commented 8 years ago

Guys, I haven't found the root cause of the issue, but I have a work around until I do. The strategy is as follows:

1) remove the exception translation filter from spring security. this is the object responsible for storing the current request into the session and the redirecting the browser to the login page 2) add a custom url mapping for 500 on spring authentication exceptions and map it to an error handler controller. The handler will function as the access denied handler and redirect to the login page. 3) in the error handler method, save the forward uri and redirect to a custom login page with the forward uri on the query string 4) in the controller method that renders the login page, pass the forward-uri that came from the access denied handler into a hidden input with the name "spring-security-redirect" in the login form. Spring will pick up this field and perform the redirect for you after a successful login.

To remove the exception translation filter, add this to the Config.groovy grails.plugin.springsecurity.filterChain.filterNames = [ 'securityContextPersistenceFilter', 'logoutFilter', 'authenticationProcessingFilter', 'rememberMeAuthenticationFilter', 'anonymousAuthenticationFilter', 'filterInvocationInterceptor' ] // filter list sans exceptionTranslationFilter

add this mapping to your URLMappings.groovy "500"(controller: "errors", action: "accessDenied", exception: org.springframework.security.access.AccessDeniedException)

If you don't have an ErrorsController.groovy, create one and add this method: def accessDenied(){ redirect uri: "/index/login?redirecturl=${forward}" } replace the uri with your login page

In your login page render the redirecturl into the form as follows:

<form ...>

the spring-security-redirect is a special form param picked up by the authentication handler and performs the redirect.

Based on my experiments, this method seem to be a good work around and drastically reduces the size of the serialized session.

Please let me know if this is successful for you.

-ben

denis111 commented 8 years ago

That's seems to work for now! But just how do i supress exception message in the output log?

kys30 commented 8 years ago

Thanks Ben. This worked for me too.

Though, I still have a concern with my cookie size. After removing the SAVED REQUEST from session, the cookie size comes around 1500b .

I see many websites (Ex: Facebook and Linkedin ) where the session cookies, which might be storing much more information are very small in size. !

Using kryo does reduces my cookie size to almost half but the serializer doesn't work for me (as you have mentioned in the docs) !

Thanks for the help -Kaushik

denis111 commented 8 years ago

Facebook definately doesn't use any generic session of any generic server/framework and has some custom implementation to store it's certain things, I think.

But about the size and serialization. Does any (de)compression applied to the cookie before saving/reading it? If not then maybe some fast algorythm wouldn't impact much the server performance? Like snappy or what is the latest fastest compressor exists...

benlucchesi commented 8 years ago

Guys,

I'm really glad to hear things are working with the fix.

Firstly, the cookie-session plugin has integrated compression. Check your settings and make sure its turned on.

Secondly, don't just shove anything into a session. Instead of storing entire objects, just store the essential elements of what you need. If you assign objects that aren't yours to the session, you won't know exactly what's in that object's graph when it gets serialized and it could be massive. Consider Exceptions - depending on how its written it may have the stack trace along references to a myriad of other objects. That's why I wrote the exception condenser - it reduces exceptions to just the string message of the exception. If you have the choice of storing an object in a session vs storing the ID of an object in a session, then just store the ID and retrieve the object when you need it.

Finally, always try to use the kryo serializer - it gives you far more control over the serialization process, is quicker and produces smaller results than the java serializer. The advantage of the java serializer is that it can serialize and deserialize objects that the kryo serializer can't (unless you tell kryo to use the java serializer for those object). If you know what objects break the kryo serializer, then write a custom serializer for those objects - there's an API for handling that situation in the plugin, check the docs. Alternatively, follow my prior advice and just store elements of the object that break kryo.

Regarding facebook or other apps and cookies session - consider for a moment what they would need to store. Identity? That can be as little as a unique ID for looking up the user or as sophisticated as the the principal and roles as with spring security. In any case, the reason that sessions are encrypted at the server (as does the cookie-session plugin) is to conceal the contents from the user and to prevent tampering so that it doesn't become an attack vector on the server.... you can guess what's in a cookie session, you can inspect the cookie session, tamper with it, etc. but if the app developer has done their job, then you won't get very far.

FYI - I've got a working version that upgrades the kryo serializer to the latest version. I should have that out in the next couple of weeks.

-ben

On Fri, Oct 16, 2015 at 4:22 AM, denis111 notifications@github.com wrote:

Facebook definately doesn't use any generic session of any generic server/framework and has some custom implementation to store it's certain things, I think.

But about the size and serialization. Does any (de)compression applied to the cookie before saving/reading it? If not then maybe some fast algorythm wouldn't impact much the server performance? Like snappy or what is the latest fastest compressor exists...

— Reply to this email directly or view it on GitHub https://github.com/benlucchesi/grails-cookie-session/issues/59#issuecomment-148688146 .

denis111 commented 8 years ago

Great news, waiting for updated kryo!. About compression: yes, i see gzip in source code but just wanted to mention that there's also fater algorythms that maybe some users might like for server performance (like lz4 one): http://java-performance.info/performance-general-compression/

double16 commented 6 years ago

May be fixed in https://github.com/double16/grails-cookie-session/tree/release/4.0.0 Session is much smaller now with kryo 4 and several kryo serializers made for spring security classes.

dependencies { compile 'org.grails.plugins:cookie-session:4.0.0.RC1' }