Thanks everyone. What do you think about the effectiveness of using Jetty to tarpit HTTP requests under the following assumptions: - Jetty is serving a Java web application - This application has a fairly regular URL pattern which can be used as an "allow-known-good" filter for valid requests. - Anything failing the known-good test yields a delayed (the "tar pit") 400 response.
I think that at the very least, failing-fast with a very small 400 response (no tarpit) is probably a good thing. Also that tarpitting failed login attempts is always recommended. If tarpitting has a place for more than failed logins, what do you think of Silvio's suggestion? Would you recommend using ContinuationSupport.getContinuation(request) as detailed here: https://www.eclipse.org/jetty/documentation/current/continuations-using.html I had almost talked myself out of other tarpitting after reading: https://en.wikipedia.org/wiki/Tarpit_(networking)#Criticism But then I found: https://www.secureworks.com/research/ddos It seems that with tarpitting, you are testing your tarpit resources against the attacker's resources. If that's a botnet, Jetty or any Java-based web server is probably the wrong tool. Botnets must be mostly blocked before DoS'ing the web server. But what about the HTTP attacks that get through that? Maybe a slow server (tar-pitted requests) could dissuade some attackers before an attack starts in earnest? On Fri, Apr 3, 2020 at 5:11 AM Silvio Bierman <sbier...@jambo-software.com> wrote: > Hello Glen, > > Sounds like you are looking for a tar pit like solution. Although the > effectiveness of that is questionable I have implemented such a thing in a > quite basic way that might suit you. > > Put the requests you don't like in async mode with something like 10s > timeout to decouple them from the handler thread and push them on a limited > size FIFO queue (I use a simple circular buffer) to prevent them from > hogging your memory. Every 5 seconds or so have a dedicated thread eat the > sufficiently (couple of seconds) old head part from the queue and complete > the requests. When the buffer overflows purged items are completed also > (this makes the handler thread complete older requests as it pushes the > newer ones onto the queue). This construct places limited constraint on > your application and somewhat stalls the requests. > > I use this for tar pitting failed login attempts. To be honest, we only do > this because some customers that perform regular pen tests on our system > prefer we "slow down" rogue login attempts. Perhaps it will fit your needs > also. > > Kind regards, > > Silvio > > > On 4/3/20 1:38 AM, Glen Peterson wrote: > > Thanks for your help. Sorry to take so long to get back. All three seem > to return some kind of blank response, or maybe they just close the > connection instantly. I was imagining that there might be a way for the > server to literally just leave the client hanging there waiting for a > response and not getting one. > > I'm looking for a response for any request that ends with ".php" or asks > for "/user/register." That's just not even a vaguely valid request for our > app and indicates some kind of script or hacker. > > I had previously approximated a truly ignored request by doing a > thread.sleep() for a somewhat random amount of time before returning 503 - > Service Unavailable SC_SERVICE_UNAVAILABLE, which was the most ambiguous > response I could give. As in, "Yeah, maybe we're a wordpress site that's > just having issues right now." > > But that temporarily dedicates a thread for an attacker that wed rather > ignore. Maybe this is why people use a Web Application Firewall - so that > their app doesn't even get these requests in the first place. The WAF that > blocks it can withstand a DDoS. I'm a little wary of letting a 3rd party > WAF inspect our traffic in the name of security. It's also another point > of failure. Maybe that's as good as it gets? The good outweighs the bad? > > Simone Bordet's is nice and quiet: > baseRequest.httpChannel.endPoint.close() > > > The other two show exceptions in the logs: > > response.sendError(-1, "We don't dignify hacking attempts with a > response.") // abruptly close the connection > > java.lang.NullPointerException > at > org.eclipse.jetty.http2.server.HttpTransportOverHTTP2.retrieveTrailers(HttpTransportOverHTTP2.java:214) > at > org.eclipse.jetty.http2.server.HttpTransportOverHTTP2.send(HttpTransportOverHTTP2.java:179) > at org.eclipse.jetty.server.HttpChannel.sendResponse(HttpChannel.java:829) > at org.eclipse.jetty.server.HttpChannel.write(HttpChannel.java:901) > at org.eclipse.jetty.server.HttpOutput.channelWrite(HttpOutput.java:283) > at org.eclipse.jetty.server.HttpOutput.complete(HttpOutput.java:479) > at org.eclipse.jetty.server.Response.completeOutput(Response.java:842) > at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:512) > at org.eclipse.jetty.server.HttpChannel.run(HttpChannel.java:335) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:135) > at > org.eclipse.jetty.http2.HTTP2Connection.produce(HTTP2Connection.java:170) > at > org.eclipse.jetty.http2.HTTP2Connection.onFillable(HTTP2Connection.java:125) > at > org.eclipse.jetty.http2.HTTP2Connection$FillableCallback.succeeded(HTTP2Connection.java:348) > at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) > at > org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:543) > at > org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:398) > at > org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:161) > at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) > at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) > at > org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:388) > at > org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806) > at > org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938) > at java.base/java.lang.Thread.run(Thread.java:834) > > > > baseRequest.httpChannel.abort(Throwable("Bogus")) > > java.lang.NullPointerException > at > org.eclipse.jetty.http2.server.HttpTransportOverHTTP2.retrieveTrailers(HttpTransportOverHTTP2.java:214) > at > org.eclipse.jetty.http2.server.HttpTransportOverHTTP2.send(HttpTransportOverHTTP2.java:179) > at org.eclipse.jetty.server.HttpChannel.sendResponse(HttpChannel.java:829) > at org.eclipse.jetty.server.HttpChannel.write(HttpChannel.java:901) > at org.eclipse.jetty.server.HttpOutput.channelWrite(HttpOutput.java:283) > at org.eclipse.jetty.server.HttpOutput.complete(HttpOutput.java:479) > at org.eclipse.jetty.server.Response.completeOutput(Response.java:842) > at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:512) > at org.eclipse.jetty.server.HttpChannel.run(HttpChannel.java:335) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) > at > org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:135) > at > org.eclipse.jetty.http2.HTTP2Connection.produce(HTTP2Connection.java:170) > at > org.eclipse.jetty.http2.server.HTTP2ServerConnection.onOpen(HTTP2ServerConnection.java:150) > at org.eclipse.jetty.io.AbstractEndPoint.upgrade(AbstractEndPoint.java:442) > at > org.eclipse.jetty.server.NegotiatingServerConnection.onFillable(NegotiatingServerConnection.java:130) > at > org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) > at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) > at > org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:543) > at > org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:398) > at > org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:161) > at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) > at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) > at > org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806) > at > org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938) > at java.base/java.lang.Thread.run(Thread.java:834) > > On Tue, Mar 17, 2020 at 4:47 AM Greg Wilkins <gr...@webtide.com> wrote: > >> >> and just to add some more options... >> >> if you are using Jetty APIs then calling abort(Throwble) on the >> HttpChannel is he best transport independent way to do a GO_AWAY style >> semantic. Doing a sendError(-1) will also trigger an abort under the >> scenes (and can be done from a servlet). >> >> Finally, throwing BadMessageException is another way to handle this. It >> will send a 400 and then close the connection. >> >> cheers >> >> >> >> On Mon, 16 Mar 2020 at 19:27, Simone Bordet <sbor...@webtide.com> wrote: >> >>> Hi, >>> >>> On Mon, Mar 16, 2020 at 5:13 PM Glen Peterson <glen.k.peter...@gmail.com> >>> wrote: >>> > >>> > My first choice would be to decide not to respond from within an >>> AbstractHandler's handle() method, after examining the >>> (HttpServlet)Request. But if there's another place we can examine the >>> request (ideally in Java), that would work too. Right now I've got some >>> code like: >>> > >>> > object MyHandler: AbstractHandler() { >>> > >>> > override fun handle(target: String, >>> > baseRequest: Request, >>> > request: HttpServletRequest, >>> > response: HttpServletResponse) { >>> > >>> > val rawPath = request.getPathInfo() >>> > >>> > // We don't have any PHP files. Any attempt to access one is >>> hacking. >>> > if ( rawPath.endsWith(".php") ) { >>> > logger.info("BOGUS Request: [${request.pathInfo}]") >>> >>> baseRequest.getHttpChannel().getEndPoint().close(); >>> >>> However, in general is not that big of a difference to send a 400 >>> (response.sendError(400)), it's more standard and will work for the >>> years in future. >>> >>> -- >>> Simone Bordet >>> ---- >>> http://cometd.org >>> http://webtide.com >>> Developer advice, training, services and support >>> from the Jetty & CometD experts. >>> _______________________________________________ >>> jetty-users mailing list >>> jetty-users@eclipse.org >>> To unsubscribe from this list, visit >>> https://www.eclipse.org/mailman/listinfo/jetty-users >>> >> >> >> -- >> Greg Wilkins <gr...@webtide.com> CTO http://webtide.com >> _______________________________________________ >> jetty-users mailing list >> jetty-users@eclipse.org >> To unsubscribe from this list, visit >> https://www.eclipse.org/mailman/listinfo/jetty-users >> > > > -- > Glen K. Peterson > (828) 393-0081 > > _______________________________________________ > jetty-users mailing listjetty-us...@eclipse.org > To unsubscribe from this list, visit > https://www.eclipse.org/mailman/listinfo/jetty-users > > > _______________________________________________ > jetty-users mailing list > jetty-users@eclipse.org > To unsubscribe from this list, visit > https://www.eclipse.org/mailman/listinfo/jetty-users > -- Glen K. Peterson (828) 393-0081
_______________________________________________ jetty-users mailing list jetty-users@eclipse.org To unsubscribe from this list, visit https://www.eclipse.org/mailman/listinfo/jetty-users