From 63e2e9c391c165ce074df4239d341b0b1962a380 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 6 Jun 2022 10:40:55 +1000 Subject: [PATCH] Fix #8067 Use nanotime for DosFilter rate tracker (#8082) * Fix #8067 Use nanotime for DosFilter rate tracker Use nano time to avoid false positives when wall clock changes. --- .../java/org/eclipse/jetty/servlets/DoSFilter.java | 12 ++++++------ .../org/eclipse/jetty/servlets/DoSFilterTest.java | 3 +-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java index 4426620987e1..cd12a373041c 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java @@ -322,7 +322,7 @@ protected void doFilter(HttpServletRequest request, HttpServletResponse response tracker = getRateTracker(request); // Calculate the rate and check if it is over the allowed limit - final OverLimit overLimit = tracker.isRateExceeded(System.currentTimeMillis()); + final OverLimit overLimit = tracker.isRateExceeded(System.nanoTime()); // Pass it through if we are not currently over the rate limit. if (overLimit == null) @@ -1182,8 +1182,8 @@ public RateTracker(ServletContext context, String filterName, String id, RateTyp } /** - * @param now the time now (in milliseconds) - * @return the current calculated request rate over the last second + * @param now the time now (in nanoseconds) used to calculate elapsed time since previous requests. + * @return the current calculated request rate over the last second if rate exceeded, else null. */ public OverLimit isRateExceeded(long now) { @@ -1201,9 +1201,9 @@ public OverLimit isRateExceeded(long now) } long rate = (now - last); - if (rate < 1000L) + if (TimeUnit.NANOSECONDS.toSeconds(rate) < 1L) { - return new Overage(Duration.ofMillis(rate), _maxRequestsPerSecond); + return new Overage(Duration.ofNanos(rate), _maxRequestsPerSecond); } return null; } @@ -1292,7 +1292,7 @@ public void run() int latestIndex = _next == 0 ? (_timestamps.length - 1) : (_next - 1); long last = _timestamps[latestIndex]; - boolean hasRecentRequest = last != 0 && (System.currentTimeMillis() - last) < 1000L; + boolean hasRecentRequest = last != 0 && TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - last) < 1L; DoSFilter filter = (DoSFilter)_context.getAttribute(_filterName); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java index ddbb3bc37226..80ad724c6adc 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java @@ -16,7 +16,6 @@ import java.net.InetSocketAddress; import java.util.Collections; import java.util.Enumeration; -import java.util.concurrent.TimeUnit; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -174,7 +173,7 @@ private boolean hitRateTracker(DoSFilter doSFilter, int sleep) throws Interrupte for (int i = 0; i < 5; i++) { Thread.sleep(sleep); - if (rateTracker.isRateExceeded(TimeUnit.NANOSECONDS.toMillis(System.nanoTime())) != null) + if (rateTracker.isRateExceeded(System.nanoTime()) != null) exceeded = true; } return exceeded;