]> WPIA git - gigi.git/commitdiff
upd: create rate limit for account creation
authorFelix Dörre <felix@dogcraft.de>
Mon, 2 May 2016 12:12:06 +0000 (14:12 +0200)
committerFelix Dörre <felix@dogcraft.de>
Mon, 2 May 2016 12:38:45 +0000 (14:38 +0200)
src/org/cacert/gigi/pages/account/certs/CertificateRequest.java
src/org/cacert/gigi/pages/main/RegisterPage.java
src/org/cacert/gigi/pages/main/Signup.java
src/org/cacert/gigi/util/RateLimit.java [new file with mode: 0644]

index 746529492146f30a0e44f23301edcbfdf24e2709..270c71781d16e0ebabaa23190b7b9e76a8f4577b 100644 (file)
@@ -33,6 +33,7 @@ import org.cacert.gigi.output.template.Scope;
 import org.cacert.gigi.output.template.SprintfCommand;
 import org.cacert.gigi.util.AuthorizationContext;
 import org.cacert.gigi.util.PEM;
+import org.cacert.gigi.util.RateLimit;
 
 import sun.security.pkcs.PKCS9Attribute;
 import sun.security.pkcs10.PKCS10;
@@ -430,6 +431,9 @@ public class CertificateRequest {
             throw error;
         }
         try {
+            if (limit.isLimitExceeded(Integer.toString(ctx.getActor().getId()))) {
+                throw new GigiApiException("Rate Limit Exceeded");
+            }
             return new Certificate(ctx.getTarget(), ctx.getActor(), subject, selectedDigest, //
                     this.csr, this.csrType, profile, SANs.toArray(new SubjectAlternateName[SANs.size()]));
         } catch (IOException e) {
@@ -438,6 +442,9 @@ public class CertificateRequest {
         return null;
     }
 
+    // 100 per 10 minutes
+    private static final RateLimit limit = new RateLimit(100, 10 * 60 * 1000);
+
     private String verifyName(GigiApiException error, PropertyTemplate nameTemp, PropertyTemplate wotUserTemp, String verifiedCN) {
         // real names,
         // possible configurations: name {y,null,?}, name=WoTUser {y,null}
index 78b1cc19faa311089970778a59d854f5c3a3b8e4..4bc2cd957fa9b7d6e0e0c88cffbf0392cc5bba09 100644 (file)
@@ -11,6 +11,7 @@ import javax.servlet.http.HttpSession;
 import org.cacert.gigi.output.template.Form;
 import org.cacert.gigi.pages.Page;
 import org.cacert.gigi.util.AuthorizationContext;
+import org.cacert.gigi.util.RateLimit;
 
 public class RegisterPage extends Page {
 
@@ -18,6 +19,9 @@ public class RegisterPage extends Page {
 
     public static final String PATH = "/register";
 
+    // 5 per 5 min
+    public static final RateLimit RATE_LIMIT = new RateLimit(50, 5 * 60 * 1000);
+
     public RegisterPage() {
         super("Register");
     }
index bb72a9cd1a44fa516624823a36b7671c7d62ea58..52a6603f76615e364229d105e85845a01c4eafdb 100644 (file)
@@ -158,6 +158,10 @@ public class Signup extends Form {
         if (isFailed(out)) {
             return false;
         }
+        if (RegisterPage.RATE_LIMIT.isLimitExceeded(req.getRemoteAddr())) {
+            outputError(out, req, "Rate Limit Exceeded");
+            return false;
+        }
         try {
             run(req, pw1);
         } catch (SQLException e) {
diff --git a/src/org/cacert/gigi/util/RateLimit.java b/src/org/cacert/gigi/util/RateLimit.java
new file mode 100644 (file)
index 0000000..46098bf
--- /dev/null
@@ -0,0 +1,73 @@
+package org.cacert.gigi.util;
+
+import java.util.HashMap;
+import java.util.TreeSet;
+
+public class RateLimit {
+
+    private class Entry implements Comparable<Entry> {
+
+        long firstAccess;
+
+        int count = 1;
+
+        String feature;
+
+        public Entry(long firstAccess, String feature) {
+            this.firstAccess = firstAccess;
+            this.feature = feature;
+        }
+
+        public void access() {
+            count++;
+        }
+
+        @Override
+        public int compareTo(Entry o) {
+            return feature.compareTo(o.feature);
+        }
+
+        public boolean isExpired() {
+            return firstAccess + time < System.currentTimeMillis();
+        }
+
+    }
+
+    private final int maxcount;
+
+    private final long time;
+
+    TreeSet<Entry> set = new TreeSet<Entry>();
+
+    HashMap<String, Entry> feat = new HashMap<>();
+
+    public RateLimit(int maxcount, long time) {
+        this.maxcount = maxcount;
+        this.time = time;
+    }
+
+    public synchronized boolean isLimitExceeded(String feature) {
+        clean();
+        Entry e = feat.get(feature);
+        if (e == null) {
+            e = new Entry(System.currentTimeMillis(), feature);
+            set.add(e);
+            feat.put(feature, e);
+        } else {
+            e.access();
+        }
+        return e.count > maxcount;
+    }
+
+    private void clean() {
+        while (set.size() > 0) {
+            Entry e = set.last();
+            if (e.isExpired()) {
+                set.remove(e);
+                feat.remove(e.feature);
+            } else {
+                return;
+            }
+        }
+    }
+}