You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Christopher Schultz <ch...@christopherschultz.net> on 2020/06/08 21:29:56 UTC

Implementing TNO (Trust No One) for Session Stores

-----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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: Implementing TNO (Trust No One) for Session Stores

Posted by Mark Thomas <ma...@apache.org>.
On 19/06/2020 14:38, Christopher Schultz wrote:
> Mark,
> 
> On 6/9/20 08:13, Mark Thomas wrote:
>> On 08/06/2020 22:29, Christopher Schultz wrote:
>>> 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.
> 
>> My instinct is that this is a fairly rare requirement at the
>> moment.
> 
> As I think more about this, I think it's important that we investigate
> this a little further. Especially because I do not think it will be
> terribly complicated.
> 
>>> 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.
> 
>> It depends which API. There are lots of 3rd-party session managers
>> so we need to be very careful. Default methods could be useful.
> 
>> I'm wondering if we need a new Filter/Valve/Interceptor style API
>> for this. Or a wrapper around an existing store. Or a wrapper
>> around an existing Manager. Or...
> 
> I've been looking at where ObjectOutputStream is being used in Tomcat
> code, and it's quite limited:
> 
> XByteBuffer (not relevant)
> DeltaManager (serves a different purpose)
> StandardManager
> JDBCStore
> FileStore
> 
> Obviously, it's the last 3 of these which are interesting to me.
> 
> StandardManager, when configured with a pathname (or left to default
> SESSIONS.ser), will use a local-file to store *all* sessions when
> Tomcat is shutting-down, and will load from that file on startup. This
> is fundamentally different from the session Store concept which deals
> with sessions individually instead of in bulk.
> 
> The Store interface and the various implementations thereof deal with
> individual session-storage.
> 
> So I think we need separate solutions for each of the two above cases,
> even if they end up sharing a lot of code (e.g. implementation of an
> encrypted wrapper).
> 
>> I think we need to look a some of the 3rd party session managers
>> out there to get an idea of how this might integrate with them. Or
>> if that is even possible.
> 
> If we can do this at the Manager/Store level (separately) then I think
> we won't disturb 3rd-party session managers. If we package the code in
> a helpful way, 3rd-party session managers could probably re-use the
> code if it makes sense to do so.
> 
> What is a little strange is that the JDBCStore and FileStore
> implementations delegate the session serialization to the
> StandardManager, probably in the spirit of code-reuse. Here is where
> the unfortunate internal Tomcat API is working against us:
> StandardManager.writeObjectData accepts an ObjectOutputStream instead
> of an OutputStream.
> 
> What if we add something like this in StandardSession:
> 
> public void writeObjectData(OutputStream out) {
>     if(encrypt) {
>       out = addEncryptionDecorator(out);
>     }
> 
>     writeObjectData(new ObjectOutputStream(out));
> }
> 
> This should not disturb any existing code.
> 
> We update the Store implementations to call
> writeObjectData(OutputStream) instead of
> writeObjectData(ObjectOutputStream). Any 3rd-party session manager can
> use addEncryptionDecorator() if it wants to, and any 3rd-party Store
> implementation can use writeObjectData(OutputStream).
> 
> StandardManager's implementation of bulk-session-storage can create a
> single encrypted stream and continue to call
> writeObjectData(ObjectOutputStream) as before.
> 
> Symmetric changes to readObjectData would be made as well.
> 
> WDYT?

Looks good.

I'm just wondering how far we need to go in making this generic /
customisable.

Mark

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


Re: Implementing TNO (Trust No One) for Session Stores

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Mark,

On 6/9/20 08:13, Mark Thomas wrote:
> On 08/06/2020 22:29, Christopher Schultz wrote:
>> 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.
>
> My instinct is that this is a fairly rare requirement at the
> moment.

As I think more about this, I think it's important that we investigate
this a little further. Especially because I do not think it will be
terribly complicated.

>> 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.
>
> It depends which API. There are lots of 3rd-party session managers
> so we need to be very careful. Default methods could be useful.
>
> I'm wondering if we need a new Filter/Valve/Interceptor style API
> for this. Or a wrapper around an existing store. Or a wrapper
> around an existing Manager. Or...

I've been looking at where ObjectOutputStream is being used in Tomcat
code, and it's quite limited:

XByteBuffer (not relevant)
DeltaManager (serves a different purpose)
StandardManager
JDBCStore
FileStore

Obviously, it's the last 3 of these which are interesting to me.

StandardManager, when configured with a pathname (or left to default
SESSIONS.ser), will use a local-file to store *all* sessions when
Tomcat is shutting-down, and will load from that file on startup. This
is fundamentally different from the session Store concept which deals
with sessions individually instead of in bulk.

The Store interface and the various implementations thereof deal with
individual session-storage.

So I think we need separate solutions for each of the two above cases,
even if they end up sharing a lot of code (e.g. implementation of an
encrypted wrapper).

> I think we need to look a some of the 3rd party session managers
> out there to get an idea of how this might integrate with them. Or
> if that is even possible.

If we can do this at the Manager/Store level (separately) then I think
we won't disturb 3rd-party session managers. If we package the code in
a helpful way, 3rd-party session managers could probably re-use the
code if it makes sense to do so.

What is a little strange is that the JDBCStore and FileStore
implementations delegate the session serialization to the
StandardManager, probably in the spirit of code-reuse. Here is where
the unfortunate internal Tomcat API is working against us:
StandardManager.writeObjectData accepts an ObjectOutputStream instead
of an OutputStream.

What if we add something like this in StandardSession:

public void writeObjectData(OutputStream out) {
    if(encrypt) {
      out = addEncryptionDecorator(out);
    }

    writeObjectData(new ObjectOutputStream(out));
}

This should not disturb any existing code.

We update the Store implementations to call
writeObjectData(OutputStream) instead of
writeObjectData(ObjectOutputStream). Any 3rd-party session manager can
use addEncryptionDecorator() if it wants to, and any 3rd-party Store
implementation can use writeObjectData(OutputStream).

StandardManager's implementation of bulk-session-storage can create a
single encrypted stream and continue to call
writeObjectData(ObjectOutputStream) as before.

Symmetric changes to readObjectData would be made as well.

WDYT?

>> 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.
>
> Symmetric encryption should be enough. Not persisting
> authentication (already an option) and not restoring expired
> sessions (already done) should go some way to mitigating replay
> attacks.

I agree that symmetric encryption is sufficient.

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

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAl7sv7wACgkQHPApP6U8
pFjSdRAAj8pcYvEAMHwKyQA/N1ysKKWtwFPhPXVCy2dAqD5Bst/e9B8Kb5JZ8DFC
6ImoD05rlQRDRlxYzDD3oUxxLoEshM6O5PqiWWAZbosqYJENE+3cNL2VlBFTTByQ
rGQb4Bsw+t58u6hoJ9RV1sDazRN/ZC0FHLXlYxxcMxgARlE3NkDOSpvPtrqMY0xc
QUTZQWENHh5l564jrjqBkvkoW2E3i0FkWZmPhi6Goe2u5m/BlBs2N9j2laq72dMw
T4Wq6I3uzH4Gf3R+nXb9WbSnwCcpksI33QGqErMOYaUQC8/W6ObHiXrKly930NeY
frVlyK+fXz035twgeTQTOMm6f1Ernq8LTTk7AM+60otu6lfU9t7u+LKXCUo2Pv7+
wnrJmRb11R97/uL0C5rg3iG1boRyNQwcmb7xAvPI+yy6BZLjN6e4iytJRfKxMcm9
1VAtfkJ1A1feuu75tFwVVr5p0pbur7OlFzagkaQQbTY5rFZjydFIL9t8kiM5xQ0H
I1IQDp7BtYfJog7Y20EIK3HEWhqcGEslhDu3caKT6oJwreRUMy+5K+4FdZlK5mDz
LvoFAM1hEFoqvabeO13RcfGUnejea2DVkS2L+5MvvNCXLsk7w8klQQxn/O1oeojG
SFLW2QmKWugzkznK7AQW61ekMwYQd+Oa2iUfqGXEFHJq7UYcwJE=
=wE5/
-----END PGP SIGNATURE-----

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


Re: Implementing TNO (Trust No One) for Session Stores

Posted by Mark Thomas <ma...@apache.org>.
On 08/06/2020 22:29, Christopher Schultz wrote:
> 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.

My instinct is that this is a fairly rare requirement at the moment.

> 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.

It depends which API. There are lots of 3rd-party session managers so we
need to be very careful. Default methods could be useful.

I'm wondering if we need a new Filter/Valve/Interceptor style API for
this. Or a wrapper around an existing store. Or a wrapper around an
existing Manager. Or...

I think we need to look a some of the 3rd party session managers out
there to get an idea of how this might integrate with them. Or if that
is even possible.

> 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.

Symmetric encryption should be enough. Not persisting authentication
(already an option) and not restoring expired sessions (already done)
should go some way to mitigating replay attacks.

Mark

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