Hello, I am using JBoss-2.4.4_Tomcat-4.0.1 and have spent some time on experimenting with security in Jboss/Tomcat. Everything works but I think I have found an issue which is unacceptable for using container managed security within my current project (and possibly other projects).
During the last couple of days I have run some tests and I am affraid that I have found what is in my eyes a security issue regarding the way tomcat/jboss tracks sessions in coordination with security.
Possibly this is a calculated risc in the J2EE specs or Jboss/Tomcat implementation, but to me it seems not acceptable for most e-commerce site. Also it could be a configuration error on my behalf, but in this case I want to make sure how to fix it and possibly help other avoiding the same problem.
Let me try to explain my findings and please give me your view on this.
Most sites have a public section of the website which anyone can visit. Once you want to purchase an item on a e-commerce website you will have to login for authentication and authorisation. Offcourse this goes together with switching to SSL, because username/passwords should never be send cleartext and any userdata should be protected, like creditcardnumbers. No problem you think, but underwater something happened during my tests which I think is not acceptable.
If I understand things correctly Jboss/Tomcat uses a cookie session tracking mechanism (JSESSIONID) to identify which HttpSession is related to this request. And the security state (identity & principals/roles) is assigned to the HttpSession. After a successful login (on the webcontainer) the identity and one or more roles are assigned to the HttpSession.
This means that (in memory) cookies are set on the client containing the JSESSIONID and is used on the serverside to relate any request to a certain HttpSession. When a user is not under SSL this cookie is send unprotected over the net. Now when someone sniffs your sessionID cookie on the Internet they can act as your session by either putting it in the requestheader or simple adding it to any url (like http://www.mysite.com/index.jsp;jessionid=12345).
Fair enough, because this session shouldn’t contain any personal/private information because if you would send this information it could also be sniffed. Therefore in the case of any sensitive info you will switch to SSL and possibly require a login.
Here the trouble starts. When you do switch between http to https, Jboss/Tomcat does not provide a new and secure cookie (which should hold a different jsessionid offcourse). This means that during the secure part of the session you keep the same jsessionid, which has been sent unprotected over the net.
So if anyone sniffed your insecure sessionid cookie, they can now take over you’re identity (including your security roles) by using this insecure jsessionid in any request. This means that they can access any business logic or private data for which you are authorised within this application!!!
Again I am not sure how this was intended in the specs, but to me this seems not secure enough when your site handles any private data. I haven’t looked at any of the sourcecode of Jboss/Tomcat and I could be doing something wrong, but it was suprisingly easy to setup this test.
There is a workaround, although it is not so elegant. When switching between non-ssl and ssl you can invalidate the non-secure session. Which Jboss/Tomcat does not seem to enforce in any way. This means that you will get a new and secure cookie (containing a different jsessionid). The biggest disadvantage would be that this would also mean that you will lose all state of the previous session, which could contain important information about the customer. The old session can no longer be abused because the session was invalidated and the HttpSession was cleared. Possibly the container could implement a mechanism that switches sessionid without loosing the session state??
I would like to here from you about your opinions.
Ps. my experience with Jboss is not that extensive and it could be that I am missing something, but I wanted to be absolutely sure.
I guess there are a few issues here.
I believe that what you say is true - if you have a session which you carry across from an non-SSL to an SSL situation, then it would be possible for someone to sniff the session ID and hijack the session.
This problem isn't really specific to J2EE or Tomcat or whatever - it's true in general. It's up to you to make sure that you make you're app secure because if you're very serious about security, then there are limitations to what the container can provide. There will always be ways of screwing up, with any technology.
There are a few things to consider.
You don't have to have a session unless you want one. When you call HttpServletRequest.getSession(true), the session is created). So it's up to you to make sure that you use SSL from the point where you start using a session.
BUT if you have multiple app contexts running in the same container, then the container will likely share the session cookie (though not session objects) between them. So, unless you have complete control over all the running applications, you have no real guarantee in any app that the session ID hasn't been passed around for ages in the clear prior to you accessing it.
To mitigate this kind of risk, most serious apps will use their own cookies after logon, to check against session information. Online banks will usually use SSL exclusively.
If you only want to have payment secured, for checking out a shopping cart or something, then make the payment gateway a separate application. In many apps, this will be an external third party in any case.
The servlet spec also mentions using SSL sessions as a means of maintaining session information in J2EE, so if SSL is used, the JSESSIONID isn't needed. I would guess that Tomcat doesn't do this though. But after your investigations, you probably know more about the internals of Tomcat security management than I do :).
As another minor point, since pre-ssl session info is so amenable to hijacking, I would doubt you would want to transfer any of it to inside the ssl session anyway. Why not do everything inside ssl from the start?
I agree with your points!. But as far as the J2EE specs go I think they are trying to make security more a deployment issue then a development issue. Now when I look at the implementation of Tomcat I think this is (at least not yet) the case.
I also agree that it is a good idea to create a new session when switching to ssl, but I would think it is the responsability of the container to enforce this (esspecially if you agree on my statement on J2EE specs).
Allthough I haven't tried this as extensive on Orion as I did on JBoss (i think i will try this), i think orion by default creates a new secure sessionID cookie when switching to ssl. Effectivelly meaning you loose your current session. This is the behaviour I would expect from Tomcat by default!! In orion you can set a shared=true setting which means that the session is shared and creates the same security issue (i think), but al least it is not default behaviour.
I am affraid that many developer/deployers (mainly on smaller projects) do not always realise that this is what happens when they switch from non-ssl to ssl?! They think they are building a secure application (when switching to ssl) without realising there are security consequences!!
Does any of you know of any setting in Tomcat that could enforce creating a new session instead of sharing the non-secure session in a secure context???
Is there anyone from the implementation team of Tomcat/Jboss who has an opinion on this, I would appreciate to know about the ideas behind the current and/or future implementation/behaviour. Thanks in advance.
teseling : I think everything said so far is correct, but one thing is not clear to me when you're comparing Tomcat with Orion (or whatever).
- either you start right from the beginning with an ssl session, as soon as the user does some interaction with the server - in this case there is no security issue.
- or, you want to have a session where the user for instance adds some things to his basket, unencrypted (presumably to generate less load on the server, I can't think of any other good reason to do it unencrypted). And then, when he clicks on 'pay' or whatever, you want to switch to an encrypted session. This way of doing things only makes sense if you're planning to use the information accumulated during the unencrypted session.
If Orion (or whatever the webserver is) is meant to generate a new session and discard the existing one, then what is the use ? In this case you've lost the previous session information, such as basket contents or whatever.
So going this way would also imply doing your complete session within SSL right from the start, doesn't it ?
So unless I'm missing something, either you do everything in SSL from the beginning; or you don't in which case you will have a security issue, no matter what the webserver is.
For the most part I agree with you, but in my scenario a user is first browsing a company website (non-secure). In many cases you still want to retain state within this browsing session, but security is not really an issue yet.
At some point the user want to perform an action that needs to be secure (in my case the entire chain from filling the shoppingbasket until acknowledgement of the order is secure). In order to be secure you switch from a non-secure to a secure ssl context (within the same web-app). I do this using a declarative J2EE 1.3 <security-constraint> together with a <transport-guarantee> setting in my web.xml.
Now the container enforces that the session is redirected on SSL, but Tomcat still uses the same JSessionID onlu now in the secure context. This means that with the old insecure sessionid someone can hyjack my secure session including authorization roles in J2EE. For instance if I would implement a webmail application, the hyjacker has now access to all my private mail!!!
I was under the impression that the container should take care of this for me (since I am using declarative security). With Orion I was used that the container did change sessionIDs in order to make the session save.
Offcourse as part of the application I can start a new secure session (and invalidate the old non-secure). But when you use declarative security I think this should be handled for you by the container. Because I could have several places in which I change between secure/loggedin and non-secure access to the webapplication.
> So unless I'm missing something, either you do everything
> in SSL from the beginning; or you don't in which case you
> will have a security issue, no matter what the webserver is.
This isn't necessarily true - the vulnerability is only through the session cookie, and this can be changed throughout the session as many times as the container wants. You could have a shopping cart full of stuff, then login with an SSL connection and checkout. The container could change the session cookie from that point without necessarily having to ditch the information. It would be transparent to the user application.
I agree that the simplest thing is to use SSL from the start, but I believe this has quite a high performance hit. Sites like Amazon allow you to fill a shopping cart before switching to SSL.
> Now the container enforces that the session is redirected on SSL, but Tomcat still uses the same JSessionID onlu now in
> the secure context. This means that with the old insecure sessionid someone can hyjack my secure session including
> authorization roles in J2EE.
I guess the bottom line is that it isn't part of the specification. If someone really has to write a seriously secure applictation, then they would be unwise to do so without getting some external auditing done in any case, not just at OS/Network level, but also at the application level, and by someone who has an in-depth knowledge of the issues and the J2EE implementations. "I thought the container would take care of it" just won't wash in practice. It would be foolish to make any assumptions that are based on anything other than in-depth knowledge. Of course this knowledge is much more readily available in open source :).
As an aside Websphere 3 was released with easily hacked, sequential, time-based session IDs without anyone noticing.
You could perhaps persuade the Tomcat developers to try and improve this, but it's not really a JBoss security issue. As I mentioned before, it would also make sense for them to use the SSLSession object to prevent session hijacking. This will be unique to a single security context and if an existing JSESSIONID was used without a matching SSL session ID, this would presumably indicate a deliberate attack. Maybe they already do this, I don't know. I'll have a look though, because I'm curious now...
If you make your secure site to be of a different domain (say you have your notsecure.mycomp.com and secure.mycomp.com) your problem just vanishes away.
When users want to go to notsecure.mycomp.com cookies are not sent at all and will only be sent at the time user makes request to the secure.mycomp.com
This way noone will be able to sniff your sessionid cookies.