'preventing abuse of API service usage

I am planning on using Laravel in my next web project, for the backend. Using the Laravel's built-in functionality I will build an API service. So my main concern now - is about the security of such service. Laravel's API throttling middleware seems to be an easy to use solution, but it doesn't quite have the flexibility that I need. Or at least I don't see if it can handle my scenario or not.

Here are my questions. Hopefully someone can answer them.

  1. is it possible to apply different throttling logic depending on whether the user is logged or not? (perform 2-3 throttle checks) Or do several different throttle checks within the same request.

  2. Where is the history kept about IPs who are calling the API? Is it in HTTP headers or some kind of cache/memcached/redis?

  3. If I want to ban an IP and then perform checks if it's banned - is there a good tutorial on how to store this kind of information? How to integrate it with throttling? Schema examples or anything? A piece of advice would be good :)

Here is a quick example of logic that I want to implement eventually:

  • route: GET: /api/invoice/1

rules:

if IP throttling is enabled 
    then I don't want to check whether user is logged in or not

if (user is unauthorized) {
    throttle by IP.
    Throttle after 10 attempts within 1 minute

    if (number of times throttled within last 5 minutes = 0) {
        Retry-After: 1 minute
    }
    else if (number of times throttled within last 10 minutes > 1) {
        Retry-After: 10 minutes
    }
    else if (number of times throttled within last 30 minutes > 3) {
        Retry-After: 3 hours
    }
    else if (number of times throttled within last 8 hours minutes > 6) {
        ban IP for 1 week!!!
    }
}
else (user is authorised) {
    if (has permission: get_invoices) {
        throttle by JWT token.
        Throttle after 100 attempts within 1 minute

        if (number of times throttled within last 5 minutes = 0) {
            Retry-After: 5 minutes
        }
        else if (number of times throttled within last 30 minutes > 1) {
            ban user!!!
        }
    }
    else (user is logged in but doesn't have necessary permission
    {
        throttle by JWT token.

        Throttle after 50 attempts within 1 minute

        // apply logic different from user who has permission
    }

}

for route N.r. 2, 3, 4 it can be a differnt logic whatsoever.

So I can not use just a single middleware like in this example, because it is based on a singlee parameter (be it IP, WTD, domain or other) and doesn't incluse any of the banning logic

Route::group(['prefix' => 'api', 'middleware' => 'throttle:2,5'], function () {
    Route::get('invoice/{id}', function () {
        return $some invoice;
    });
});

I would like to receive some feedback on this matter. I am planning on going global :)



Solution 1:[1]

I got some really simple answers for you :)

Custom throttling logic

Laravel already provides you with a specific class (App/Providers/RouteServiceProvider) where you can specify your custom throttling logic based on your needs. Here is an example provided by the official documentation:

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
 
/**
 * Configure the rate limiters for the application.
 *
 * @return void
 */
protected function configureRateLimiting()
{
    RateLimiter::for('global', function (Request $request) {
        return Limit::perMinute(1000);
    });
}

For more information please check the docs: Defining Rate Limiters

History for IPs

The documentation doesn't show anything related to this, I suggest you to include the column ip in the User model and store their current ip after logging in or registering. But if you're referring to it so you can add it to your rate limiting logic, you can include (to the Limit class) the method ->by($request->user()?->id ?: $request->ip()); which is the default one for the API throttling.

Banning users by IP

I suggest you to use the package made by cybercog laravel-ban which includes methods to check if a user is banned, ban by specific email, ip, etc. I've been using it for some apps I made and it's really cool and easy to install and use.

Solution 2:[2]

Here's my response to your questions:

  1. is it possible to apply different throttling logic depending on whether the user is logged or not? (perform 2-3 throttle checks) Or do several different throttle checks within the same request.

    Yes, you can make a custom middleware and then call the throttle middleware from your custom middleware based on your desired logic

  2. Where is the history kept about IPs who are calling the API? Is it in HTTP headers or some kind of cache/memcached/redis?

    Laravel doesn't log IP addresses out of the box. Again you can make a custom middleware to do so. To get the IP address, you can use $request->ip()

  3. If I want to ban an IP and then perform checks if it's banned - is there a good tutorial on how to store this kind of information? How to integrate it with throttling? Schema examples or anything? A piece of advice would be good :)

    Yes, you can build this logic into the custom middleware that you write for Q2. To store/retrieve banned IP addresses, you can either use the cache or DB. To "integrate" with throttling, you can just use both middlewares

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Francisco Solis
Solution 2 Paras