From: Felix Dörre Date: Mon, 2 May 2016 12:12:06 +0000 (+0200) Subject: upd: create rate limit for account creation X-Git-Url: https://code.wpia.club/?p=gigi.git;a=commitdiff_plain;h=a64b40f37a1845a4b9c5f1c0e962babca4b2d291 upd: create rate limit for account creation --- diff --git a/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java b/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java index 74652949..270c7178 100644 --- a/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java +++ b/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java @@ -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} diff --git a/src/org/cacert/gigi/pages/main/RegisterPage.java b/src/org/cacert/gigi/pages/main/RegisterPage.java index 78b1cc19..4bc2cd95 100644 --- a/src/org/cacert/gigi/pages/main/RegisterPage.java +++ b/src/org/cacert/gigi/pages/main/RegisterPage.java @@ -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"); } diff --git a/src/org/cacert/gigi/pages/main/Signup.java b/src/org/cacert/gigi/pages/main/Signup.java index bb72a9cd..52a6603f 100644 --- a/src/org/cacert/gigi/pages/main/Signup.java +++ b/src/org/cacert/gigi/pages/main/Signup.java @@ -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 index 00000000..46098bf5 --- /dev/null +++ b/src/org/cacert/gigi/util/RateLimit.java @@ -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 { + + 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 set = new TreeSet(); + + HashMap 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; + } + } + } +}