summaryrefslogtreecommitdiff
path: root/zxingorg/src/main/java/com/google
diff options
context:
space:
mode:
authorSean Owen <srowen@gmail.com>2019-03-12 21:25:15 +0300
committerSean Owen <srowen@gmail.com>2019-03-12 21:25:15 +0300
commit8a53ade692c9514b597c40efe5d3be506402c49a (patch)
tree8a4817fc47c41b1ca1d2cffb882cae770c0a70e3 /zxingorg/src/main/java/com/google
parentbc645c50bb18fb3b30a3ffaa74d042ce1ada616d (diff)
downloadzxing-8a53ade692c9514b597c40efe5d3be506402c49a.tar.xz
More sophisticated load protection, plus tests
Diffstat (limited to 'zxingorg/src/main/java/com/google')
-rw-r--r--zxingorg/src/main/java/com/google/zxing/web/ChartDoSFilter.java32
-rw-r--r--zxingorg/src/main/java/com/google/zxing/web/DecodeDoSFilter.java32
-rw-r--r--zxingorg/src/main/java/com/google/zxing/web/DecodeServlet.java20
-rw-r--r--zxingorg/src/main/java/com/google/zxing/web/DoSFilter.java40
-rw-r--r--zxingorg/src/main/java/com/google/zxing/web/DoSTracker.java10
5 files changed, 103 insertions, 31 deletions
diff --git a/zxingorg/src/main/java/com/google/zxing/web/ChartDoSFilter.java b/zxingorg/src/main/java/com/google/zxing/web/ChartDoSFilter.java
new file mode 100644
index 000000000..b1d5d569d
--- /dev/null
+++ b/zxingorg/src/main/java/com/google/zxing/web/ChartDoSFilter.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing.web;
+
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.annotation.WebInitParam;
+
+/**
+ * Protect the /chart endpoint from too many requests.
+ */
+@WebFilter(urlPatterns = {"/w/chart"}, initParams = {
+ @WebInitParam(name = "maxAccessPerTime", value = "250"),
+ @WebInitParam(name = "accessTimeSec", value = "500"),
+ @WebInitParam(name = "maxEntries", value = "10000")
+})
+public final class ChartDoSFilter extends DoSFilter {
+ // no additional implementation
+}
diff --git a/zxingorg/src/main/java/com/google/zxing/web/DecodeDoSFilter.java b/zxingorg/src/main/java/com/google/zxing/web/DecodeDoSFilter.java
new file mode 100644
index 000000000..d09172c86
--- /dev/null
+++ b/zxingorg/src/main/java/com/google/zxing/web/DecodeDoSFilter.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing.web;
+
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.annotation.WebInitParam;
+
+/**
+ * Protect the /decode endpoint from too many requests.
+ */
+@WebFilter(urlPatterns = {"/w/decode"}, initParams = {
+ @WebInitParam(name = "maxAccessPerTime", value = "60"),
+ @WebInitParam(name = "accessTimeSec", value = "180"),
+ @WebInitParam(name = "maxEntries", value = "10000")
+})
+public final class DecodeDoSFilter extends DoSFilter {
+ // no additional implementation
+}
diff --git a/zxingorg/src/main/java/com/google/zxing/web/DecodeServlet.java b/zxingorg/src/main/java/com/google/zxing/web/DecodeServlet.java
index 65ee067a9..b7af4ccd0 100644
--- a/zxingorg/src/main/java/com/google/zxing/web/DecodeServlet.java
+++ b/zxingorg/src/main/java/com/google/zxing/web/DecodeServlet.java
@@ -59,6 +59,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Timer;
+import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -89,8 +90,8 @@ import javax.servlet.http.Part;
fileSizeThreshold = 1 << 23, // ~8MB
location = "/tmp")
@WebServlet(value = "/w/decode", loadOnStartup = 1, initParams = {
- @WebInitParam(name = "maxAccessPerTime", value = "150"),
- @WebInitParam(name = "accessTimeSec", value = "300"),
+ @WebInitParam(name = "maxAccessPerTime", value = "120"),
+ @WebInitParam(name = "accessTimeSec", value = "120"),
@WebInitParam(name = "maxEntries", value = "10000")
})
public final class DecodeServlet extends HttpServlet {
@@ -141,8 +142,17 @@ public final class DecodeServlet extends HttpServlet {
long accessTimeMS = TimeUnit.MILLISECONDS.convert(accessTimeSec, TimeUnit.SECONDS);
int maxEntries = Integer.parseInt(servletConfig.getInitParameter("maxEntries"));
- timer = new Timer("DecodeServlet");
- destHostTracker = new DoSTracker(timer, maxAccessPerTime, accessTimeMS, maxEntries);
+ String name = getClass().getSimpleName();
+ timer = new Timer(name);
+ destHostTracker = new DoSTracker(timer, name, maxAccessPerTime, accessTimeMS, maxEntries);
+ // Hack to try to avoid odd OOM due to memory leak in JAI?
+ timer.scheduleAtFixedRate(
+ new TimerTask() {
+ @Override
+ public void run() {
+ System.gc();
+ }
+ }, 0L, TimeUnit.MILLISECONDS.convert(10, TimeUnit.MINUTES));
}
@Override
@@ -433,10 +443,8 @@ public final class DecodeServlet extends HttpServlet {
try {
throw savedException == null ? NotFoundException.getNotFoundInstance() : savedException;
} catch (FormatException | ChecksumException e) {
- log.info(e.toString());
errorResponse(request, response, "format");
} catch (ReaderException e) { // Including NotFoundException
- log.info(e.toString());
errorResponse(request, response, "notfound");
}
return;
diff --git a/zxingorg/src/main/java/com/google/zxing/web/DoSFilter.java b/zxingorg/src/main/java/com/google/zxing/web/DoSFilter.java
index 0586779b6..db5ad26cb 100644
--- a/zxingorg/src/main/java/com/google/zxing/web/DoSFilter.java
+++ b/zxingorg/src/main/java/com/google/zxing/web/DoSFilter.java
@@ -16,19 +16,18 @@
package com.google.zxing.web;
+import com.google.common.base.Preconditions;
+
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import javax.servlet.annotation.WebFilter;
-import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Timer;
-import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
/**
@@ -37,12 +36,7 @@ import java.util.concurrent.TimeUnit;
*
* @author Sean Owen
*/
-@WebFilter(urlPatterns = {"/w/decode", "/w/chart"}, initParams = {
- @WebInitParam(name = "maxAccessPerTime", value = "150"),
- @WebInitParam(name = "accessTimeSec", value = "300"),
- @WebInitParam(name = "maxEntries", value = "10000")
-})
-public final class DoSFilter implements Filter {
+public abstract class DoSFilter implements Filter {
private Timer timer;
private DoSTracker sourceAddrTracker;
@@ -50,18 +44,16 @@ public final class DoSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
int maxAccessPerTime = Integer.parseInt(filterConfig.getInitParameter("maxAccessPerTime"));
+ Preconditions.checkArgument(maxAccessPerTime > 0);
int accessTimeSec = Integer.parseInt(filterConfig.getInitParameter("accessTimeSec"));
+ Preconditions.checkArgument(accessTimeSec > 0);
long accessTimeMS = TimeUnit.MILLISECONDS.convert(accessTimeSec, TimeUnit.SECONDS);
int maxEntries = Integer.parseInt(filterConfig.getInitParameter("maxEntries"));
- timer = new Timer("DoSFilter");
- sourceAddrTracker = new DoSTracker(timer, maxAccessPerTime, accessTimeMS, maxEntries);
- timer.scheduleAtFixedRate(
- new TimerTask() {
- @Override
- public void run() {
- System.gc();
- }
- }, 0L, TimeUnit.MILLISECONDS.convert(15, TimeUnit.MINUTES));
+ Preconditions.checkArgument(maxEntries > 0);
+
+ String name = getClass().getSimpleName();
+ timer = new Timer(name);
+ sourceAddrTracker = new DoSTracker(timer, name, maxAccessPerTime, accessTimeMS, maxEntries);
}
@Override
@@ -79,9 +71,17 @@ public final class DoSFilter implements Filter {
}
private boolean isBanned(HttpServletRequest request) {
- String remoteIPAddress = request.getHeader("x-forwarded-for");
+ String remoteHost = request.getHeader("x-forwarded-for");
+ if (remoteHost != null) {
+ int comma = remoteHost.indexOf(',');
+ if (comma >= 0) {
+ remoteHost = remoteHost.substring(0, comma);
+ }
+ remoteHost = remoteHost.trim();
+ }
+ // Non-short-circuit "|" below is on purpose
return
- (remoteIPAddress != null && sourceAddrTracker.isBanned(remoteIPAddress)) ||
+ (remoteHost != null && sourceAddrTracker.isBanned(remoteHost)) |
sourceAddrTracker.isBanned(request.getRemoteAddr());
}
diff --git a/zxingorg/src/main/java/com/google/zxing/web/DoSTracker.java b/zxingorg/src/main/java/com/google/zxing/web/DoSTracker.java
index 9884ea8af..2cbbefe94 100644
--- a/zxingorg/src/main/java/com/google/zxing/web/DoSTracker.java
+++ b/zxingorg/src/main/java/com/google/zxing/web/DoSTracker.java
@@ -35,7 +35,7 @@ final class DoSTracker {
private final long maxAccessesPerTime;
private final Map<String,AtomicLong> numRecentAccesses;
- DoSTracker(Timer timer, final int maxAccessesPerTime, long accessTimeMS, int maxEntries) {
+ DoSTracker(Timer timer, final String name, final int maxAccessesPerTime, long accessTimeMS, int maxEntries) {
this.maxAccessesPerTime = maxAccessesPerTime;
this.numRecentAccesses = new LRUMap<>(maxEntries);
timer.schedule(new TimerTask() {
@@ -51,8 +51,8 @@ final class DoSTracker {
accessIt.remove();
} else {
// Else it exceeded the max, so log it (again)
- log.warning("Blocking " + entry.getKey() + " (" + count + " outstanding)");
- // Reduce count of accesses held against the IP
+ log.warning(name + ": Blocking " + entry.getKey() + " (" + count + " outstanding)");
+ // Reduce count of accesses held against the host
count.getAndAdd(-maxAccessesPerTime);
}
}
@@ -70,8 +70,8 @@ final class DoSTracker {
synchronized (numRecentAccesses) {
count = numRecentAccesses.get(event);
if (count == null) {
- count = new AtomicLong();
- numRecentAccesses.put(event, count);
+ numRecentAccesses.put(event, new AtomicLong(1));
+ return false;
}
}
return count.incrementAndGet() > maxAccessesPerTime;