All Projects → sief → Play Guard

sief / Play Guard

Play2 module for rate limiting, based on token bucket algorithm

Programming Languages

scala
5932 projects

Projects that are alternatives of or similar to Play Guard

Bottleneck
Job scheduler and rate limiter, supports Clustering
Stars: ✭ 1,113 (+804.88%)
Mutual labels:  rate-limiting
Scala Play Angular Seed
🍀 Scala Play 2.7.x + Angular 8 with Angular CLI seed project with full-fledged build process
Stars: ✭ 85 (-30.89%)
Mutual labels:  play-framework
Play Pdf
A PDF module for the Play framework
Stars: ✭ 108 (-12.2%)
Mutual labels:  play-framework
Vos backend
vangav open source - backend; a backend generator (generates more than 90% of the code needed for big scale backend services)
Stars: ✭ 71 (-42.28%)
Mutual labels:  play-framework
Ring Ratelimit
Rate limiting middleware for Clojure Ring
Stars: ✭ 78 (-36.59%)
Mutual labels:  rate-limiting
Governor
A rate-limiting library for Rust (formerly ratelimit_meter)
Stars: ✭ 99 (-19.51%)
Mutual labels:  rate-limiting
Play Spark Scala
Stars: ✭ 51 (-58.54%)
Mutual labels:  play-framework
Istio Workshop
In this workshop, you'll learn how to install and configure Istio, an open source framework for connecting, securing, and managing microservices, on Google Kubernetes Engine, Google’s hosted Kubernetes product. You will also deploy an Istio-enabled multi-service application
Stars: ✭ 120 (-2.44%)
Mutual labels:  rate-limiting
Redisratelimiter
Redis Based API Access Rate Limiter
Stars: ✭ 80 (-34.96%)
Mutual labels:  rate-limiting
Speedbump
A Redis-backed rate limiter in Go
Stars: ✭ 107 (-13.01%)
Mutual labels:  rate-limiting
Webapithrottle
ASP.NET Web API rate limiter for IIS and Owin hosting
Stars: ✭ 1,180 (+859.35%)
Mutual labels:  rate-limiting
Lila
♞ lichess.org: the forever free, adless and open source chess server ♞
Stars: ✭ 10,315 (+8286.18%)
Mutual labels:  play-framework
Play2 Html5tags
HTML5 form tags module for Play Framework
Stars: ✭ 101 (-17.89%)
Mutual labels:  play-framework
Nekobin
Elegant and open-source pastebin service
Stars: ✭ 61 (-50.41%)
Mutual labels:  rate-limiting
Sentinel Golang
Sentinel Go version (Reliability & Resilience)
Stars: ✭ 1,817 (+1377.24%)
Mutual labels:  rate-limiting
Spark Submit Ui
This is a based on playframwork for submit spark app
Stars: ✭ 53 (-56.91%)
Mutual labels:  play-framework
Sentinel Cpp
C++ implementation of Sentinel
Stars: ✭ 91 (-26.02%)
Mutual labels:  rate-limiting
Guzzle Advanced Throttle
A Guzzle middleware that can throttle requests according to (multiple) defined rules. It is also possible to define a caching strategy, e.g. get the response from cache when the rate limit is exceeded or always get a cached value to spare your rate limits. Using wildcards in host names is also supported.
Stars: ✭ 120 (-2.44%)
Mutual labels:  rate-limiting
Kebs
Scala library to eliminate boilerplate
Stars: ✭ 113 (-8.13%)
Mutual labels:  play-framework
Axios Rate Limit
Rate limit for axios
Stars: ✭ 106 (-13.82%)
Mutual labels:  rate-limiting

Play2 Guard Module

Maven Maven Maven Maven

Play2 module for blocking and throttling abusive requests.

  • throttling specific Actions based on request attributes (e.g. IP address)

  • throttling specific Actions based on request attributes (e.g. IP address) and failure rate (e.g. HTTP status or any other Result attribute)

  • global IP address whitelisting/blacklisting

  • global request throttling

Target

This module targets the Scala version of Play 2.x.x

Rate Limit Algorithm

Based on the token bucket algorithm: http://en.wikipedia.org/wiki/Token_bucket

Getting play-guard

For Play 2.8.x:

  "com.digitaltangible" %% "play-guard" % "2.5.0"

For Play 2.7.x:

  "com.digitaltangible" %% "play-guard" % "2.4.0"

For Play 2.6.x:

  "com.digitaltangible" %% "play-guard" % "2.2.0"

For Play 2.5.x:

  "com.digitaltangible" %% "play-guard" % "2.0.0"

For Play 2.4.x:

  "com.digitaltangible" %% "play-guard" % "1.6.0"

For Play 2.3.x:

  "com.digitaltangible" %% "play-guard" % "1.4.1"

1. RateLimitAction

Action function/filter for request and failure rate limiting specific actions. You can derive the bucket key from the request.

The rate limit functions/filters all take a RateLimiter instance as the first parameter:

  class RateLimiter(size: Int, rate: Float, logPrefix: String = "", clock: Clock = CurrentTimeClock)

It holds the token bucket group with the specified size and rate and can be shared between actions if you want to use the same bucket group for various actions.

1.1 Request rate limit

There is a general ActionFilter for handling any type of request so you can chain it behind you own ActionTransformer:

    /**
     * ActionFilter which holds a RateLimiter with a bucket for each key returned by function f.
     * Can be used with any Request type. Useful if you want to use content from a wrapped request, e.g. User ID
     *
     * @param rateLimiter
     * @param keyFromRequest
     * @param rejectResponse
     * @param bypass
     * @param executionContext
     * @tparam R
     */
    class RateLimitActionFilter[R[_] <: Request[_]](
      rateLimiter: RateLimiter,
      keyFromRequest: R[_] => Any,
      rejectResponse: R[_] => Future[Result],
      bypass: R[_] => Boolean = (_: R[_]) => false
    )(
      implicit val executionContext: ExecutionContext
    ) extends ActionFilter[R]

There are also two convenience filters:

IP address as key (from the sample app):

  // allow 3 requests immediately and get a new token every 5 seconds
  private val ipRateLimitFilter = IpRateLimitFilter[Request](
    new RateLimiter(3, 1f / 5, "test limit by IP address"), { r: RequestHeader =>
      Future.successful(TooManyRequests(s"""rate limit for ${r.remoteAddress} exceeded"""))
    }
  )

  def limitedByIp: Action[AnyContent] = (Action andThen ipRateLimitFilter) {
    Ok("limited by IP")
  }

Action parameter as key (from the sample app):

  // allow 4 requests immediately and get a new token every 15 seconds
  private val keyRateLimitFilter: String => RateLimitActionFilter[Request] =
    KeyRateLimitFilter[String, Request](
      new RateLimiter(4, 1f / 15, "test by token"),
      key => _ => Future.successful(TooManyRequests(s"""rate limit for '$key' exceeded"""))
    )

  def limitedByKey(key: String): Action[AnyContent] =
    (Action andThen keyRateLimitFilter(key)) {
      Ok("limited by token")
    }

1.2 Error rate limit

There is a general ActionFunction for handling any type of request so you can chain it behind your own ActionTransformer and determine failure from the Result:

    /**
     * ActionFunction which holds a RateLimiter with a bucket for each key returned by function keyFromRequest.
     * Tokens are consumed only by failures determined by function resultCheck. If no tokens remain, requests with this key are rejected.
     * Can be used with any Request type. Useful if you want to use content from a wrapped request, e.g. User ID
     *
     * @param rateLimiter
     * @param keyFromRequest
     * @param resultCheck
     * @param rejectResponse
     * @param bypass
     * @param executionContext
     * @tparam R
     */
    class FailureRateLimitFunction[R[_] <: Request[_]](
      rateLimiter: RateLimiter,
      keyFromRequest: R[_] => Any,
      resultCheck: Result => Boolean,
      rejectResponse: R[_] => Future[Result],
      bypass: R[_] => Boolean = (_: R[_]) => false
    )(implicit val executionContext: ExecutionContext)
        extends ActionFunction[R, R]

The convenience action HttpErrorRateLimitAction limits the HTTP error rate for each IP address. This is for example useful if you want to prevent brute force bot attacks on authentication requests.

From the sample app:

  // allow 2 failures immediately and get a new token every 10 seconds
  private val httpErrorRateLimitFunction =
    HttpErrorRateLimitFunction[Request](new RateLimiter(2, 1f / 10, "test failure rate limit"), _ => Future.successful(BadRequest("failure rate exceeded")))

  def failureLimitedByIp(fail: Boolean): Action[AnyContent] =
    (Action andThen httpErrorRateLimitFunction) {
      if (fail) BadRequest("failed")
      else Ok("Ok")
    }

1.3 Integration with Silhouette

https://www.silhouette.rocks/docs/rate-limiting

2. GuardFilter

Filter for global rate limiting and IP address whitelisting/blacklisting.

Note: this global filter is only useful if you don't have access to a reverse proxy like nginx where you can handle these kind of things

2.1 Rules

Rejects requests based on the following rules:

if IP address is in whitelist => let pass
else if IP address is in blacklist => reject with ‘403 FORBIDDEN’
else if IP address rate limit exceeded => reject with ‘429 TOO_MANY_REQUEST’
else if global rate limit exceeded => reject with ‘429 TOO_MANY_REQUEST’

2.2 Usage

For compile time DI:

class ApplicationComponents(context: Context) extends BuiltInComponentsFromContext(context) with PlayGuardComponents {

  override lazy val httpFilters: Seq[EssentialFilter] = Seq(guardFilter)
}

Runtime DI with Guice:

@Singleton
class Filters @Inject()(env: Environment, guardFilter: GuardFilter) extends DefaultHttpFilters(guardFilter)

The filter uses the black/whitelists from the configuration by default. You can also plug in you own IpChecker implementation. With runtime time DI you have to disable the default module in your application.conf and bind your implementation in your app's module:

play {
  modules {
    disabled += "com.digitaltangible.playguard.PlayGuardIpCheckerModule"
  }
}

2.2 Configuration

playguard {
  filter {
    enabled = true
    global {
      bucket {
        size = 100
        rate = 100
      }
    }
    ip {
      whitelist = ["1.1.1.1", "2.2.2.2"]
      blacklist = ["3.3.3.3", "4.4.4.4"]
      bucket {
        size = 50
        rate = 50
      }
    }
  }
}

3. Configuring the remote IP address

IP-based rate limits will use RequestHeader.remoteAddress as the address of the client. Depending on how you have configured Play this may be the actual remote address of clients connecting directly, or it may be read from the common X-Forwarded-For or Forwarded headers that are set by proxies and load balancers.

If you are using a reverse proxy (e.g. nginx, HAProxy or an AWS ELB) in front of your application, you should take care to configure the play.http.forwarded.trustedProxies setting, otherwise all requests will be rate-limited against the IP address of the upstream proxy (definitely not what you want).

For scenarios where you don't know your immediate connection's IP address beforehand (to configure it as a trusted proxy) but can still trust it, e.g. on Heroku, there is a custom RequestHandler XForwardedTrustImmediateConnectionRequestHandler which replaces the immediate connection with the last IP address in the X-Forwarded-For header (RFC 7239 is not supported). This handler can be configured as described here

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].