5

I would like to prevent DDOS attacks on my spring boot 2 web application and I came across the framework bucket4j (bucket4j-github). My application will run on heroku, and there they suggested doing so (Heroku-Link)

So far so good. I am now trying to implement bucket4j and I would expect after that, in case I press F5 very fast and frequent, something would happen, an error will occure or something like that. But it behaves as it would without the bucket4j framework, the request has been all answered.

My target is to limit the rate from an ip. Currently I just tried from localhost.

What I have so far:

pom.xml

    <dependency>
        <groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
        <artifactId>bucket4j-spring-boot-starter</artifactId>
        <version>0.1.15</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
    </dependency>
    <dependency><!-- Somehow I needed that since bucket4j--> 
        <groupId>javax.interceptor</groupId>
        <artifactId>javax.interceptor-api</artifactId>
        <version>1.2.2</version>
    </dependency>

application.properties

# CACHE
spring.cache.jcache.config=classpath:ehcache.xml

# RATE LIMIT
bucket4j.enabled=true
bucket4j.filters[0].cache-name=buckets
bucket4j.filters[0].filter-method=servlet
bucket4j.filters[0].url=/* 
bucket4j.filters[0].rate-limits[0].bandwidths[0].capacity=10
bucket4j.filters[0].rate-limits[0].bandwidths[0].time=1
bucket4j.filters[0].rate-limits[0].bandwidths[0].unit=minutes
bucket4j.filters[0].rate-limits[0].expression=getRemoteAddress()
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval=0
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval-unit=minutes

ehcache.xml

<config ... >
    <cache alias="buckets">
        <expiry><ttl unit="seconds">3600</ttl></expiry>
        <heap unit="entries">1000000</heap>
    </cache>
</config>

What am I missing, or did I missunderstand the framework? Thanks for hints.

Michael Hegner
  • 5,555
  • 9
  • 38
  • 64
  • Did you fix this? –  Oct 25 '19 at 12:02
  • Hi, I am currently working on another project. This here is still on my todo. I did not try out yet more. But I will come back here, when I worked on it. – Michael Hegner Oct 25 '19 at 14:49
  • Hi @michael-hegner, did you solve the problem? I have a similar issue and did not find the soludion: https://stackoverflow.com/questions/66216856/how-to-use-spring-boot-bucket4j-library – Peters_ Feb 16 '21 at 12:56

6 Answers6

0

I think you need to change this line to :

bucket4j.filters[0].url = .*

Good Luck!

AmirBll
  • 1,081
  • 1
  • 13
  • 25
Esfand55
  • 1
  • 1
0

Adding @EnableCaching in my Spring Boot configuration and using bucket4j.filters[0].url=.* was enough to fix the problem.

Italo Borssatto
  • 15,044
  • 7
  • 62
  • 88
0

Make sure maven is importing the dependency. Adding the version number in pom.xml solved the problem for me:

    <dependency>
        <groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
        <artifactId>bucket4j-spring-boot-starter</artifactId>
        <version>0.2.0</version>
    </dependency>

By not adding the version number in pom.xml maven was not importing the dependency. No errors were showing but the rate limiting was not working.

Codrut
  • 435
  • 4
  • 11
0

I am doing in application.properties and working for me, you can try this!

#This is for Api Rate Limit
#Reference -: https://github.com/MarcGiffing/bucket4j-spring-boot-starter#bucket4j-properties
spring.cache.type=jcache
spring.cache.jcache.config=classpath:ehcache.xml
bucket4j.enabled=true
bucket4j.filters[0].cache-name=buckets
bucket4j.filters[0].filter-method=servlet
bucket4j.filters[0].http-response-body={ "message": "Too many requests" }
bucket4j.filters[0].url=.*
bucket4j.filters[0].strategy=first
bucket4j.filters[0].rate-limits[0].expression=getRemoteAddr()
bucket4j.filters[0].rate-limits[0].bandwidths[0].capacity=10
bucket4j.filters[0].rate-limits[0].bandwidths[0].time=1
bucket4j.filters[0].rate-limits[0].bandwidths[0].unit=minutes
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval=0
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval-unit=minutes

and dont forget to add @EnableCaching in any @Configuration file

iamkdblue
  • 3,448
  • 2
  • 25
  • 43
0

Following configuration works for me:

1) pom.xml

    <dependency>
        <groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
        <artifactId>bucket4j-spring-boot-starter</artifactId>
        <version>0.4.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
    </dependency>

2) ehcache.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.ehcache.org/v3"
    xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">
<cache alias="buckets">
    <expiry>
        <ttl unit="seconds">3600</ttl>
    </expiry>
    <heap unit="entries">1000000</heap>
</cache>

3) application.properties

### Bucket4j
bucket4j.enabled=true
bucket4j.filters[0].cache-name=buckets
bucket4j.filters[0].filter-method=servlet
bucket4j.filters[0].http-response-body={ "message": "Too many requests" }
bucket4j.filters[0].url=.*
bucket4j.filters[0].strategy=first
bucket4j.filters[0].rate-limits[0].bandwidths[0].capacity=10
bucket4j.filters[0].rate-limits[0].bandwidths[0].time=1
bucket4j.filters[0].rate-limits[0].bandwidths[0].unit=minutes
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval=0
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval-unit=minutes

### Ehcache
spring.cache.jcache.config=classpath:ehcache.xml

Make sure @EnableCaching is added in your configuration or main class.

kkorat
  • 13
  • 3
0

Here follows my single configuration class that prevents DOS attacks:

import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Refill;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Configuration
public class HttpSecurityConfig implements WebMvcConfigurer {

    private final Map<String, Bucket> cache;

    public HttpSecurityConfig() {
        cache = new ConcurrentHashMap<>();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HandlerInterceptor() {
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
                String IPAddress = request.getRemoteAddr();
                System.out.println("Remote Address: " + IPAddress);

                updateCache(IPAddress);

                if (!isRequestRateOk(IPAddress)) {
                    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                    return false;
                }
                return true;
            }
        });
    }

    private void updateCache(String IPAddress) {
        cache.putIfAbsent(IPAddress,
                Bucket.builder()
                    .addLimit(Bandwidth.classic(5, Refill.intervally(5, Duration.ofMinutes(1)))) // Set your request rate limit
                    .build());
    }

    private boolean isRequestRateOk(String IPAddress) {
        return cache.get(IPAddress).tryConsume(1);
    }
}

Dependency used: bucket4j-core https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core

Reference: https://www.baeldung.com/spring-bucket4j

Matheus Santz
  • 538
  • 6
  • 7