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 2019/05/09 16:52:09 UTC

Punishing bad clients with delays

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

All,

What are the options we might have to "punish" an HTTP client that we
don't like for some reason?

Specifically, I'd like to be able to write a servlet that ties-up the
response to the client for a while for some bad behavior. For example,
maybe lots of authentication attempts or some other criteria. Maybe
even just a single bad authentication attempt.

I'm thinking of something along these lines:

    public void doGet(...) {

        ...

        if(shouldPunishClient(...)) {
            request.setAttribute("delay-client", Boolean.TRUE);
            return;
        }

        ...
    }

Or maybe even specify a time-out.

Then, Tomcat observes that the servlet or filter wants to put the
response into the penalty box and, instead of flushing the response
and (possibly) closing the connection, it just sits-around for a
while, keeping the connection open.

The poller usually waits for data to become available on either end of
the connection and pushes the bytes. How complicated would it be to
put connections into a queue where they wait some amount of time
before being flushed/closed/returned to the connection pool? In this
case, the only stimulus for taking action is the passage of time, not
arrival of data on a stream.

Any thoughts about how this could be done?

Clearly, a simple Thread.sleep() would do the trick in terms of just
making the client wait, but the point would be to make the client wait
without a performance impact on the server.

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

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAlzUWrkACgkQHPApP6U8
pFg1rg/9Fe3hI2bup1VCz9MqM+ObSWQjXLJnaIsBfeZUX5p/QTz44A6sbvuwh392
tDlLMUXFUpNFuThVBT059Ypiwi8X80BCuQ313GQ4XP+AVEGrWig1cQ1MHekm2jGX
LUaREGPAG60KJXrcf8oeg+k+aXijQfwpEIjMBs1ssQT+9wKB8PZ5s8sVdxyFjZaQ
Gs54IjLVCfQBCKczOPqfPFyxtSjZX9xZsDk1dw3D912UXtYEph9oW6+8lFz9/vap
WnFn2WTPoGvwx7xMH+F+51CjGtfBTa7NEWmVWjpUzmmByMLhGAF/+1HrKtcxMbtt
xC5RDmSGbSmXlwDFHTOpGHtETUfJb/FpoBXD4S7S9vU9M/ltCsmaWprmg22d/nWu
dmWsg3V5CVMreP24b6bR2NuMkJ6qyZn1htFxm7maTEnASozNo8C7udVjj8iH9NY0
Rr51U1z7Dy8tl10Wp7wL0jvdK3uXl1qJki3rfsGHTOuBw2DP5apb9t7NaUYGAAX6
8BUNOnze1kJpB70Np6+an+i1Shps5et7yoPG26PShC2FzFYfLLmv5OcJFlmXq3zy
Y9h9V0UI34+LCc+Efzw63PP2FqINCMXOGrHpQHxFkQ3iVm2gM8Vt6mQcuHw8aXio
S6+0wA0tU8s0d4X6bWmHX1S0JA7CMX4oaeMRlrw0TRSdnC1uFiY=
=/xXV
-----END PGP SIGNATURE-----

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


Re: Punishing bad clients with delays

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

Igal,

On 5/14/19 15:38, Igal @ Lucee.org wrote:
> Chris,
> 
> On 5/14/2019 12:15 PM, Christopher Schultz wrote:
>> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
>> 
>> All,
>> 
>> bump
>> 
>> It's hard to see anything with all the commit messages :)
>> 
>> On 5/9/19 12:52, Christopher Schultz wrote:
>>> All,
>>> 
>>> What are the options we might have to "punish" an HTTP client
>>> that we don't like for some reason?
>>> 
>>> Specifically, I'd like to be able to write a servlet that
>>> ties-up the response to the client for a while for some bad
>>> behavior. For example, maybe lots of authentication attempts or
>>> some other criteria. Maybe even just a single bad
>>> authentication attempt.
> 
> How do you identify the bad actor on subsequent requests?  By its
> IP address?

I'm not sure I'd bother. Making a client wait 10 seconds for each bad
password attempt might be good enough. Sure, they can use NIO and
launch a million threads on their end but I can use mod_qos on my end.

>>> I'm thinking of something along these lines:
>>> 
>>> public void doGet(...) {
>>> 
>>> ...
>>> 
>>> if(shouldPunishClient(...)) {
>>> request.setAttribute("delay-client", Boolean.TRUE); return; }
>>> 
>>> ... }
>>> 
>>> Or maybe even specify a time-out.
>>> 
>>> Then, Tomcat observes that the servlet or filter wants to put
>>> the response into the penalty box and, instead of flushing the 
>>> response and (possibly) closing the connection, it just
>>> sits-around for a while, keeping the connection open.
> 
> Wouldn't that punish Tomcat by keeping the connection open?  Open
> the door for DDoS attacks?

No, this is the point. Tie-up the connection, but not the thread.

> I would think that a better way to do it is to flush and close the 
> request immediately, and then block the IP address for X seconds.

That can be done through other means (e.g. fail2ban).

>>> The poller usually waits for data to become available on either
>>> end of the connection and pushes the bytes. How complicated
>>> would it be to put connections into a queue where they wait
>>> some amount of time before being flushed/closed/returned to the
>>> connection pool? In this case, the only stimulus for taking
>>> action is the passage of time, not arrival of data on a
>>> stream.
>>> 
>>> Any thoughts about how this could be done?
> 
> You mean as part of the NIO implementation?

Yes, something like that. Instead of closing and returning the
connection to the pool, put it in another "timeout" pool for a bit and
then close/return it after some timeout.

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

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAlzbK18ACgkQHPApP6U8
pFgJphAAruPfn0xW8GCyObHNTVJzU4LxBar52QNY8Q4Espp+qZRyT/OpuMsLEpDW
xlyq2Au4Uh625jX/EzCshm/Tbe9JSNOWx668sae7LkDkX708ZA1mgGbyo6J669L3
avOz4j6Bt7Yn4OC9mRm2vu6BYCOhlpe6WHYkZEsC7n73kAf9CqhqMlOa01qM1BZr
PDNp/tLz6MJfSBROJHvB4Bj/0Ga00aoqxHv8x0oHDqmUKDyJs370u3MVtvxtUpqx
V3Md+f12CBxtkj1HkfcNOW3/S1gYJLG3syd2NITdWs1y+E8WUvXyDkynwt+pfbDw
KGJzhyLbbQlbFmAawns9J/dgBLX8nFwvR3vqoFA1qVmeblSmdn1CHAl/sNmpZnz6
m+wgDkEbJ9L55MsyNS0qhnHNqcVLypPpHcEtqtri56ZMR6d0Vib9pntctkI0vYQc
QiLGJUi2BhNnuP2n2AmtV9ANfoFGbGun/3/vO3Kj+C+LnW5n3X+MeNSrdGEVSem7
qBeAGAfS0z9WcpMnCafMjeC6ZqaOqBvp1PhJ+2pK6n8WtxCnpqnk181q2lDYmpnZ
EGOsU08LigVMs4YlSs7ELxtyu+CLeRV8XEL+VvQ+0eG1TGFckJC6EgznggbALIro
wDmKy7I0cvGBKynKBaJuOFlPTbOq4jDK/N/O7kIPfRwuV2EflV0=
=pRck
-----END PGP SIGNATURE-----

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


Re: Punishing bad clients with delays

Posted by Mark Thomas <ma...@apache.org>.
On 14/05/2019 21:57, Christopher Schultz wrote:
> Mark,
> 
> On 5/14/19 15:47, Mark Thomas wrote:
>> On 14/05/2019 20:38, Igal @ Lucee.org wrote:
>>> On 5/14/2019 12:15 PM, Christopher Schultz wrote:
> 
>> <snip/>
> 
>>>>> Then, Tomcat observes that the servlet or filter wants to put
>>>>> the response into the penalty box and, instead of flushing
>>>>> the response and (possibly) closing the connection, it just
>>>>> sits-around for a while, keeping the connection open.
>>>
>>> Wouldn't that punish Tomcat by keeping the connection open?  Open
>>> the door for DDoS attacks?
> 
>> I don't think so.
> 
>> An open connection alone isn't going to be enough to trigger a DoS
>> (on a reasonable configured server).
> 
>> It won't make an existing DoS any worse. You'd still need DoS
>> protection.
> 
>> If you do it right, the client will just think the server is being
>> slow.
> 
>>> I would think that a better way to do it is to flush and close
>>> the request immediately, and then block the IP address for X
>>> seconds.
> 
>> I'd suggest putting the request into async mode with a predefined 
>> timeout and a listener to handle the timeout.
> 
>> That way, no extra Tomcat plumbing is required - and your solution
>> is portable across Servlet containers.
> 
> That is interesting, but I'd want to trigger it on authentication
> failure. If using Tomcat's authentication, I don't think the
> application has an opportunity to intercept, does it?
> 
> I guess a Filter could work, but the Filter needs to know that the
> authentication failed. Can a Filter switch a connection from "normal"
> more to async mode?

Use a custom error page. Have that be a servlet. Put the request in
async mode. On timeout have the listener dispatch to a
servlet/JSP/static file that displays the error message.

Should work with any authentication scheme, any realm, Tomcat provided
or otherwise as long as it uses the error page mechanism (which it should).

And yes, a filter can put a request into async mode but that should not
be necessary.

One caveat - I haven't tested any of this.

Mark

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


Re: Punishing bad clients with delays

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

Mark,

On 5/14/19 15:47, Mark Thomas wrote:
> On 14/05/2019 20:38, Igal @ Lucee.org wrote:
>> On 5/14/2019 12:15 PM, Christopher Schultz wrote:
> 
> <snip/>
> 
>>>> Then, Tomcat observes that the servlet or filter wants to put
>>>> the response into the penalty box and, instead of flushing
>>>> the response and (possibly) closing the connection, it just
>>>> sits-around for a while, keeping the connection open.
>> 
>> Wouldn't that punish Tomcat by keeping the connection open?  Open
>> the door for DDoS attacks?
> 
> I don't think so.
> 
> An open connection alone isn't going to be enough to trigger a DoS
> (on a reasonable configured server).
> 
> It won't make an existing DoS any worse. You'd still need DoS
> protection.
> 
> If you do it right, the client will just think the server is being
> slow.
> 
>> I would think that a better way to do it is to flush and close
>> the request immediately, and then block the IP address for X
>> seconds.
> 
> I'd suggest putting the request into async mode with a predefined 
> timeout and a listener to handle the timeout.
> 
> That way, no extra Tomcat plumbing is required - and your solution
> is portable across Servlet containers.

That is interesting, but I'd want to trigger it on authentication
failure. If using Tomcat's authentication, I don't think the
application has an opportunity to intercept, does it?

I guess a Filter could work, but the Filter needs to know that the
authentication failed. Can a Filter switch a connection from "normal"
more to async mode?

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

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAlzbK7wACgkQHPApP6U8
pFgoPQ//b9wibl2BumN7Savozi5W1lfXxXzWGKpVzchTEG3tT0QNPy7HJkN5Fybz
M/OSGFaic/x6FCANzQiK4hgOPlnmjFsadIXmaE/kzHNWOvy6uwWhSlehry3AulIt
D8obm4tQwyzRAMad0I0lxUDuhL4KwvAaPSgCWmNJL0SQ57i9TqfI5LgexYEdTtO4
cQ08M7jsDnVjmN2FXXh9hW5LARJvG9pRYno15vjwh8DHeDVDe6UU48xxdSNIvhs8
RCJJs77bL6YIxeBO8d4o1w+2fW6dazT1hzd5WgCA+Vk0P6PEEF+9nkDSlsjMPbgU
tsxvmt0CDJcGP/xBHVj4ChyLbxSworWDhqlfSkbZzNckIGhnw8RCZKiwp0ceHsXB
/eMndn0NI1SnXzxbOQshjGgmhFfkr1pskq2OoXLOficIGIvrQQkd+ZPxdsfeDLKc
SBAaks0Z+4yiK3YGQ4qQ1EcIBvzEouN/Bq7jKkkTTPngkYsGSVw/0ho7ZMeHWZA3
a8aXrliAfcNgKfqWk+IRsK0W7Bqy6UC2bFVneF2qFRNfcd70l90mp4ifSyPwJfQL
5263lIqudlc+oowhOMtkgEhBlqUlcBZ17iJLqSOoR9IG1+DmrmMmjZ4zL3ngCHPc
hYN8nEO7VeSEIUcy2V54LlIaLL4uPS5XRn2XnaTzMUsWlOIgw70=
=GWCI
-----END PGP SIGNATURE-----

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


Re: Punishing bad clients with delays

Posted by Mark Thomas <ma...@apache.org>.
On 14/05/2019 20:38, Igal @ Lucee.org wrote:
> On 5/14/2019 12:15 PM, Christopher Schultz wrote:

<snip/>

>>> Then, Tomcat observes that the servlet or filter wants to put the
>>> response into the penalty box and, instead of flushing the
>>> response and (possibly) closing the connection, it just sits-around
>>> for a while, keeping the connection open.
> 
> Wouldn't that punish Tomcat by keeping the connection open?  Open the
> door for DDoS attacks?

I don't think so.

An open connection alone isn't going to be enough to trigger a DoS (on a
reasonable configured server).

It won't make an existing DoS any worse. You'd still need DoS protection.

If you do it right, the client will just think the server is being slow.

> I would think that a better way to do it is to flush and close the
> request immediately, and then block the IP address for X seconds.

I'd suggest putting the request into async mode with a predefined
timeout and a listener to handle the timeout.

That way, no extra Tomcat plumbing is required - and your solution is
portable across Servlet containers.

Mark

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


Re: Punishing bad clients with delays

Posted by "Igal @ Lucee.org" <ig...@lucee.org>.
Chris,

On 5/14/2019 12:15 PM, Christopher Schultz wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
>
> All,
>
> bump
>
> It's hard to see anything with all the commit messages :)
>
> On 5/9/19 12:52, Christopher Schultz wrote:
>> All,
>>
>> What are the options we might have to "punish" an HTTP client that
>> we don't like for some reason?
>>
>> Specifically, I'd like to be able to write a servlet that ties-up
>> the response to the client for a while for some bad behavior. For
>> example, maybe lots of authentication attempts or some other
>> criteria. Maybe even just a single bad authentication attempt.

How do you identify the bad actor on subsequent requests?  By its IP 
address?

>> I'm thinking of something along these lines:
>>
>> public void doGet(...) {
>>
>> ...
>>
>> if(shouldPunishClient(...)) { request.setAttribute("delay-client",
>> Boolean.TRUE); return; }
>>
>> ... }
>>
>> Or maybe even specify a time-out.
>>
>> Then, Tomcat observes that the servlet or filter wants to put the
>> response into the penalty box and, instead of flushing the
>> response and (possibly) closing the connection, it just sits-around
>> for a while, keeping the connection open.

Wouldn't that punish Tomcat by keeping the connection open?  Open the 
door for DDoS attacks?

I would think that a better way to do it is to flush and close the 
request immediately, and then block the IP address for X seconds.

>> The poller usually waits for data to become available on either end
>> of the connection and pushes the bytes. How complicated would it be
>> to put connections into a queue where they wait some amount of
>> time before being flushed/closed/returned to the connection pool?
>> In this case, the only stimulus for taking action is the passage of
>> time, not arrival of data on a stream.
>>
>> Any thoughts about how this could be done?

You mean as part of the NIO implementation?

>> Clearly, a simple Thread.sleep() would do the trick in terms of
>> just making the client wait, but the point would be to make the
>> client wait without a performance impact on the server.

If you really want to punish a client then send back a "302 
http://aol.com" ;-)

Best,

Igal



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


Re: Punishing bad clients with delays

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

All,

bump

It's hard to see anything with all the commit messages :)

On 5/9/19 12:52, Christopher Schultz wrote:
> All,
> 
> What are the options we might have to "punish" an HTTP client that
> we don't like for some reason?
> 
> Specifically, I'd like to be able to write a servlet that ties-up
> the response to the client for a while for some bad behavior. For
> example, maybe lots of authentication attempts or some other
> criteria. Maybe even just a single bad authentication attempt.
> 
> I'm thinking of something along these lines:
> 
> public void doGet(...) {
> 
> ...
> 
> if(shouldPunishClient(...)) { request.setAttribute("delay-client",
> Boolean.TRUE); return; }
> 
> ... }
> 
> Or maybe even specify a time-out.
> 
> Then, Tomcat observes that the servlet or filter wants to put the 
> response into the penalty box and, instead of flushing the
> response and (possibly) closing the connection, it just sits-around
> for a while, keeping the connection open.
> 
> The poller usually waits for data to become available on either end
> of the connection and pushes the bytes. How complicated would it be
> to put connections into a queue where they wait some amount of
> time before being flushed/closed/returned to the connection pool?
> In this case, the only stimulus for taking action is the passage of
> time, not arrival of data on a stream.
> 
> Any thoughts about how this could be done?
> 
> Clearly, a simple Thread.sleep() would do the trick in terms of
> just making the client wait, but the point would be to make the
> client wait without a performance impact on the server.
> 
> -chris
> 
> ---------------------------------------------------------------------
>
> 
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: dev-help@tomcat.apache.org
> 
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAlzbE9wACgkQHPApP6U8
pFi/Ew/9FxbZMlSr0OZPlh8g7dbQa8tGbvXJD+zRo27dW15oYtUkA4S3nWjhR67S
90T4N4uH+BmKMfHJwVC+Kp7LjFa9GP5g6sLAdJcnZSgriURkY+3f5UIO42GDjaCg
Wxm1UjnD/DuYMlW1M/HsyJZ9ps6+0X6vtZwJtBzxJJC+66WDOuI0SefnCJ0Gavbi
Or1julT0JT3oOuQYOk7mVgBL92jVOvACkQGAgCg4nnIpcXiyM8g0G/J9qLKSE4n+
S6wdTNaYkOlJ9vgCqTbx/8HkjHdNV0Riif+jqYG8vFvETvP6W87MfutBbiV1tZUR
Z/Cno494WADV24VU22hbxax8YF7HYCMASeUoZoP1fcSsgJ/HbVVftV2AKcbDJ7QO
6ktUXsbh+hVNUZaxQ1Z4KW2sRrmlAKQ0Cdr/dSRRuKCTEuA2wGZmDSSQrvRtz+ND
McVw183m6V0aKnzBQXnrq7UJ/iO5G+UquBTtrQHT7mo9Zf24Sdj20d29te23B2Fi
ODl4P0I4b0ROXoBElLjHAQHjCizbMMStnzR9/d5LJQmjnP1RlBVpHUxpBEglTIrR
pheqvHoWFJ/glWdzB34TzLzX3nnBuax/+ZyIlvEkZSeeLws+5PE49riGYB9+CZO/
9xzykbJKcl5rEOW6tU2TDCyc4jiADMptIkWjpt0JovZXAma6vCo=
=eE5w
-----END PGP SIGNATURE-----

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