Add rate limiting

This commit is contained in:
Moxie Marlinspike 2018-12-02 17:07:35 -08:00
parent a3545ce551
commit c6eb306691
4 changed files with 31 additions and 3 deletions

View File

@ -29,6 +29,9 @@ public class RateLimitsConfiguration {
@JsonProperty
private RateLimitConfiguration voiceDestinationDaily = new RateLimitConfiguration(10, 10.0 / (24.0 * 60.0));
@JsonProperty
private RateLimitConfiguration smsVoiceIp = new RateLimitConfiguration(1000, 1000);
@JsonProperty
private RateLimitConfiguration verifyNumber = new RateLimitConfiguration(2, 2);
@ -95,6 +98,10 @@ public class RateLimitsConfiguration {
return voiceDestinationDaily;
}
public RateLimitConfiguration getSmsVoiceIp() {
return smsVoiceIp;
}
public RateLimitConfiguration getVerifyNumber() {
return verifyNumber;
}

View File

@ -110,9 +110,10 @@ public class AccountController {
@Timed
@GET
@Path("/{transport}/code/{number}")
public Response createAccount(@PathParam("transport") String transport,
@PathParam("number") String number,
@QueryParam("client") Optional<String> client)
public Response createAccount(@PathParam("transport") String transport,
@PathParam("number") String number,
@HeaderParam("X-Forwarded-For") String requester,
@QueryParam("client") Optional<String> client)
throws IOException, RateLimitExceededException
{
if (!Util.isValidNumber(number)) {
@ -120,6 +121,13 @@ public class AccountController {
throw new WebApplicationException(Response.status(400).build());
}
try {
rateLimiters.getSmsVoiceIpLimiter().validate(requester);
} catch (RateLimitExceededException e) {
logger.info("Rate limited exceeded: " + transport + ", " + number + ", " + requester);
return Response.ok().build();
}
switch (transport) {
case "sms":
rateLimiters.getSmsDestinationLimiter().validate(number);

View File

@ -25,6 +25,7 @@ public class RateLimiters {
private final RateLimiter smsDestinationLimiter;
private final RateLimiter voiceDestinationLimiter;
private final RateLimiter voiceDestinationDailyLimiter;
private final RateLimiter smsVoiceIpLimiter;
private final RateLimiter verifyLimiter;
private final RateLimiter pinLimiter;
@ -53,6 +54,10 @@ public class RateLimiters {
config.getVoiceDestinationDaily().getBucketSize(),
config.getVoiceDestinationDaily().getLeakRatePerMinute());
this.smsVoiceIpLimiter = new RateLimiter(cacheClient, "smsVoiceIp",
config.getSmsVoiceIp().getBucketSize(),
config.getSmsVoiceIp().getLeakRatePerMinute());
this.verifyLimiter = new RateLimiter(cacheClient, "verify",
config.getVerifyNumber().getBucketSize(),
config.getVerifyNumber().getLeakRatePerMinute());
@ -122,6 +127,10 @@ public class RateLimiters {
return smsDestinationLimiter;
}
public RateLimiter getSmsVoiceIpLimiter() {
return smsVoiceIpLimiter;
}
public RateLimiter getVoiceDestinationLimiter() {
return voiceDestinationLimiter;
}

View File

@ -49,6 +49,7 @@ public class AccountControllerTest {
private RateLimiters rateLimiters = mock(RateLimiters.class );
private RateLimiter rateLimiter = mock(RateLimiter.class );
private RateLimiter pinLimiter = mock(RateLimiter.class );
private RateLimiter smsVoiceIpLimiter = mock(RateLimiter.class );
private SmsSender smsSender = mock(SmsSender.class );
private DirectoryQueue directoryQueue = mock(DirectoryQueue.class);
private MessagesManager storedMessages = mock(MessagesManager.class );
@ -80,6 +81,7 @@ public class AccountControllerTest {
when(rateLimiters.getVoiceDestinationLimiter()).thenReturn(rateLimiter);
when(rateLimiters.getVerifyLimiter()).thenReturn(rateLimiter);
when(rateLimiters.getPinLimiter()).thenReturn(pinLimiter);
when(rateLimiters.getSmsVoiceIpLimiter()).thenReturn(smsVoiceIpLimiter);
when(timeProvider.getCurrentTimeMillis()).thenReturn(System.currentTimeMillis());
@ -106,6 +108,7 @@ public class AccountControllerTest {
resources.getJerseyTest()
.target(String.format("/v1/accounts/sms/code/%s", SENDER))
.request()
.header("X-Forwarded-For", "127.0.0.1")
.get();
assertThat(response.getStatus()).isEqualTo(200);
@ -120,6 +123,7 @@ public class AccountControllerTest {
.target(String.format("/v1/accounts/sms/code/%s", SENDER))
.queryParam("client", "ios")
.request()
.header("X-Forwarded-For", "127.0.0.1")
.get();
assertThat(response.getStatus()).isEqualTo(200);