-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

All,

Tomcat stores sessions without any encryption and/or authentication,
and anyone with write-access to the session-store can poison a session
and mount an attack. This kind of attack is (arguably appropriately)
declared to be outside of the scope of Tomcat's responsibilities,
because the system administrator should arrange for appropriate
access-controls to whatever storage medium is being used.

Note that sessions can also be read from such a store, of course, but
I'm more concerned with a privilege-elevation attack, here and not a
loss of privacy. It turns out that the solution to one problem can
solve them both.

If you want to be as  paranoid as possible (and why not?), you'll want
to make sure that your session persistence mechanism isn't readable by
anyone but Tomcat. I'm sure there are use-cases for making those
session stores readable outside of Tomcat, but then again, those
people aren't asking Tomcat to provide secure session storage.

It would be simple to encrypt (or sign) the session-data and decrypt
(or validate) the data coming back in when reloading.

Of course, it would be a deployment headache because it's another
shared secret that needs to be deployed to all servers in e.g. a
cluster. I'll be talking to Rémy about his cloud provider for clusters
to see if we can do things like trade-around cluster-encryption keys
via a cloud manage r(e.g. Kubernetes), and then it seems logical that
we could do the same kind of thing for the session manager, too.
Environments without such orchestration would have to arrange to
distribute their shared secrets in some other way.

This could be implemented either at the Store level or -- even better
IMO -- at the StandardSession level, since
StandardSession.wrireObjectData/StandardSession.readObjectData can do
anything it likes to its own data such as signing or encrypting. No
interfaces would have to change.

I didn't see an opportunity to install any kind of
shim/interceptor/decorator into the existing pipeline to add this
"outside" of either the Session or the Store without any API change,
so the above idea seemed to me to be the best way to look at
implementing such as thing.

The interface for Session doesn't help at all, since this
facet (session persistence) is only introduced at the StandardSession
level. Also, the interface is basically:

writeObjectData(ObjectOutputStream)
readObjectData(ObjectInputStream)

In order to provide arbitrary manipulations, we could introduce a new
interface:

interface DataMassager {
  writeObjectData(ObjectOutputStream)
  readObjectData(ObjectInputStream)
}

Then we just wrap these things around the existing implementations.
Maybe the DataMassager is a field in StandardSession.

I generally like the idea of an interceptor, but with a stream-based
API -- especially when the stream class isn't very generic -- it's
difficult to do. If we were able to change from
Object(In|Out)putStream to (In|Out)putStream or just simply
writeObjectData(byte[]), then various interceptors could mutate the
data arbitrarily on the way in or out (or, likely, both).

If we could get away from Object(In|Out)putStream, I think that would
be a win.

We might be able to do that by introducing new API methods in
Session.java:

public void writeObjectData(OutputStream);
public void readObjectData(InputStream);

Those can, by default, just wrap an Object(In|Out)putStream around
those streams and call the existing code. But other implementations
could use the generic streams directly.

But without an API change, I think we are going to have to have a
single session-data mutator object. Stacking things up will have to be
an exercise for someone who wants something beyond the complexity I
expect to introduce, which is simply to encrypt data in the persisted
session-store.

If Tomcat encrypts session data with a symmetric key (shared with any
other Tomcat instance which would need to read the session data from
the same store), then we can guarantee that session data loaded by
Tomcat was generated by Tomcat. (Or at least was generated by code
which knew the key. We can only do so much.) Such encryption protects
the data from being viewed by unauthorized parties or from being
forged and/or manipulated.

The only thing I can think of that it will not prevent is replay
attacks: grabbing a copy of a stored session and then re-injecting it
into the session-store. I'm not sure there is an attack against Tomcat
hidden in there, but certainly there is an attack against the
application in there. Applications could version sessions or add
timestamps to things as a mitigation against session-replay attacks.

Tomcat could add replay-mitigations in a few ways, but I'm not
entirely sure these are worth is. In the spirit of academic
navel-observation, let me lay out a few ways that could be done.

First, we could version sessions. Each time a session is written-out,
its version number is incremented. Or a timestamp is added. When
loading the session, the in-memory session version or timestamp is
consulted and anything that is older than current will be ignored.
This is great as long as Tomcat has the session information in memory
already, which is NOT a given.

Other thoughts I had included using file-metadata of some kind as a
corroborating factor, but if this is going to live in a serialization
method, then there is no context of a file or anything else like that
present. So whatever mechanism is being used needs to be stored in the
serialized session data itself.

I think that's enough for now. So the questions are:

1. Does anyone really want Tomcat to be worried about this stuff? I
know the answer is "some people care" but I want to get a sense of how
many actually care. So if you think this would be a good thing to
implement in one way or another, please speak up.

2. If we implement this, is it okay to change the API to do so? I
think we can do this in a backward-compatible way so that we don't
have to e.g. use an ObjectOutputStream to write a byte[] which has
been encrypted after using another ObjectOutputStream to generate
those bytes for storage.

3. Is encryption "enough", or should we try to implement some kind of
replay-mitigations? I don't think we'll ever be able to completely
close this hole because (a) Tomcat can't be expected to have a priori
information about the session before it's being loaded (e.g. after
restart) and (b) all the validation information must be inside the
stored session data. I can't think of a way to avoid a replay attack
short of maintaining yet another database of session-versions for
validation. I can see a man in the corner wearing an "Over-Engineering
Police Force" uniform staring at me intently.

Thanks everyone for reading this and providing any feedback you may have
.

- -chris
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAl7erdQACgkQHPApP6U8
pFhc9w/9E55cFOAkz6uYwhdFlAYKZQSjS2xdpsavfZzLO0EE2InosBDKlKvxblW2
pnoPGwFIrI5gGyccONlmOB96XtQYsgYDfhoN854MwryAatc0hOmwItNJN39fhj0M
Ae2UovjqkwpgLy5MFP6topb8KT6cVj1jCmKSDLLMIx1bz8VhKNjDZPcfzqOM0PO/
/kshyUrsmUC2Q3FSab+dhEGcOz4hoJRGnmFYn2NjG9FzXn5+sOJWll3yHvlfVFZp
9l9OZfZnUvfJQRYtzGZBpqpZJCKUDboN1+/1xaHFtZPjyYawNUiYUkkNgMBzUz2Q
8uSYd2+tCfxD6CQfWi/aFUqxJWuJ/ehoYQ0z2phlbAxEfWuUgMryvqmJrsL+MVOO
s0nm31/+2oRrhjspjsJE45Xuvx6EMMy52nxUw3IR6YZr9JEKEnsXRvjGhOZjAVG+
Jc1pBskJo6L0CRIOWrdhbRVL5i74xZbsYqvofwbGhTshjZPdPfMh876sVgIdKTUZ
lqoWt0aqsTjmdnPbTOs6UgKu25iTI2u3A2O4GRlpPDFaubL8nsIfhpvIa8679lYx
YCGtkx5ieErCqla4Wfo/MdvEHcoGmOcdwRyx7OLKN6CsIELsdt98UpPT+scTogF2
0dLy8o7RxG9tLrAIGIrK3cCGCsAXIypA3rXFnR2CuwNp84LXTHU=
=0NFi
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to