preventing abuse of API service usage - php

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.
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.
Where is the history kept about IPs who are calling the API? Is it in HTTP headers or some kind of cache/memcached/redis?
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 :)

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.

Here's my response to your questions:
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
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()
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

Related

How to prevent automated requests to my Laravel/Lumen api?

So, I intend to completely separate my back-end from my front-end. I am learning about Laravel/Lumen API and I intend to return my database data in JSON format to be used by my front-end developers.
I have read several similar threads on Stack Overflow and watched some YouTube videos. Most of them suggested that I should generate a token for "authorized" users. However, the problem is that my project does not have a login system. All of my users are guest users. So, I can't first authorize a person and then generate a token for them.
From what I have understood (which could be flawed), Laravel API follows a RESTful system. So, it is stateless and I can't use CSRF token to check if a request comes from a submitted form and it is not automated. So, what other options do I have?
The reason that I want to separate automated requests from requests coming from forms is that sometimes I have to do heavy processing on some requests and I don't want an automated script to send mass requests and causes a DOS attack.
Any help is appreciated.
Rate limiting can help prevent automated scripts. Laravel has this implemented by default via the Throttle middleware. Default throttle is 60:1, throttle:60,1, translating to throttle if 60 attempts are registered within 1 minute.
This middleware is applied to all routes, however, you can override this for individual routes and define custom values for number of attempts and time. Following example adapted from documentation configures the route to throttle if there's 30 attempts within 1 minute:
Route::middleware('auth:api', 'throttle:30,1')->group(function () {
Route::get('/user', function () {
//
});
});
There are other configuration options, please do refer to the documentation for more information on that.
https://laravel.com/docs/7.x/routing#rate-limiting
How does Laravel check that a guest user has sent too many requests?
In very basic terms, Laravel keeps track of hits on a particular endpoint/domain by a particular IP in the application cache. The request domain and the IP are used as the cache key. Every time an endpoint is hit, no of attempts, stored in the cache, is incremented. If the no of attempts reaches the maximum number of allowed attempts within the time window specified in the throttle config applied on the route, that IP will be locked out for a while.
Attempts are automatically cleared if there's no new hit in the time window.

How Laravel Passport works in laravel 5.3?

After watching laracast video relating to passport,i understood that passport is used to authenticate our own api.Still i have confusion regarding passport
1.How to validate authentication request for get ,post ,put and delete.Suppose if i pass token in my get url user can easily see and use that token.
2.Can i restrict the number of request to particular user to use my api ?
3.if any one decode the android app then they use that api token.In this case how we can protect ?
if any think wrong in my question please forgive.I am not much comfortable about passport and api routing in laravel 5.3
Thank you
Yes you pass your token to each request. Like explained here: https://laravel.com/docs/master/passport#passing-the-access-token
Yes, you would do that using Middleware. I suggest you inspire yourself with the Illuminate\Routing\Middleware\ThrottleRequests class.
You can refresh a specific token if you notice it's been stolen or something... But it's clearly not safe to store the client_id and client_secret in a mobile app.
Passport is built on top of League OAuth2 server, you should get familiar with it if you want to go in depth and read on security regarding Oauth2, it's a bit out of the scope for a question here. To keep it simple, use the built-in functionality in Laravel 5.3, SSL/TLS on the server to secure the communication between the app and the server and you'll most probably be fine unless you do some really strange stuff. OAuth2 is really robust and is used by many major players in the field so don't worry to much about the security.
It might be a bit strange to get a grip of having to pass a token to each request if you're used to traditional ways of authentication, there is a really good article about it which explains how it works on Scotch: The Ins and Outs of Token Based Authentication
You can protect routes using middleware. Passport includes an authentication guard that validates the access tokens upon the incoming requests, Example:
Route::get('/api/user', function () {
//
})->middleware('auth:api');
There is a rate limiting built in Larael that limits the rate at which any API requester can make requests. As you might have guessed, you should also use a middleware for this, for laravel it's the throttle middleware that you can use, example code (with /api as prefix):
Route::group(['prefix' => 'api', 'middleware' => 'throttle'], function () {
Route::get('user', function () {
return Person::all();
});
});
The default throttle is to 60 attempts per minute and disables access for a minute if the user hits the limit.
If you make a request to this route, you will now see the following lines in the response header:
HTTP/1.1 200 OK
... other headers here ...
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
You can of course customize the throttle middleware, if you want to limit it to 10 attempts per minute, this is how you would do it:
Route::group(['prefix' => 'api', 'middleware' => 'throttle:10'], function () {
Route::get('user', function () {
return User::all();
});
});
You can also add a second parameter which decides the number of minutes until they can try again, you would do 'throtttle:10,10' instead.

Laravel: Difference Between Route Middleware and Policy

Developing an app with laravel I realised that what can be done with Policy can exactly be done with Middleware. Say I want to prevent a user from updating a route if he/she is not the owner of the information, I can easily check from the route and can do the same from the policy.
So my question is why should I use policy over middleware and vice versa
I'm currently going through a small refactor with my roles, permissions and routes and asked myself the same question.
At the surface level, it appears true middleware and policies perform the same general idea. Check if a user can do what they are doing.
For reference here's the laravel docs...
Middleware
"May I see this? May I go here?"
HTTP middleware provide a convenient mechanism for filtering HTTP
requests entering your application. For example, Laravel includes a
middleware that verifies the user of your application is
authenticated. If the user is not authenticated, the middleware will
redirect the user to the login screen. However, if the user is
authenticated, the middleware will allow the request to proceed
further into the application.
Of course, additional middleware can be written to perform a variety
of tasks besides authentication. A CORS middleware might be
responsible for adding the proper headers to all responses leaving
your application. A logging middleware might log all incoming requests
to your application.
https://laravel.com/docs/master/middleware#introduction
In my reading, Middleware is about operating at the request level. In the terms of "Can this user see a page?", or "Can this user do something here?"
If so, it goes to the controller method associated with that page. Interestingly enough, Middleware may say, "Yes you may go there, but I'll write down that you are going." Etc.
Once it's done. It has no more control or say in what the user is doing. Another way I think of it as the middleperson.
Policies
"Can I do this? Can I change this?"
In addition to providing authentication services out of the box,
Laravel also provides a simple way to organize authorization logic and
control access to resources. There are a variety of methods and
helpers to assist you in organizing your authorization logic, and
we'll cover each of them in this document.
https://laravel.com/docs/master/authorization#introduction
Policies however, appear to be more concerned with doing. Can the user update any entry, or only theirs?
These questions seem fit for a controller method where all the calls to action on a resource are organized. Retrieve this object, store or update the article.
As tjbb mentioned, middleware can make routes very messy and hard to manage. This is an example from my routes file:
The problem
Route::group(['middleware' =>'role:person_type,person_type2',], function () {
Route::get('download-thing/{thing}', [
'as' => 'download-thing',
'uses' => 'ThingController#download'
]);
});
This gets very hard to read in my route file!
Another approach with policies
//ThingController
public function download(Thing $thing)
{
//Policy method and controller method match, no need to name it
$this->authorize($thing);
//download logic here....
}
Route middleware allows you to apply request handling to a large range of routes, instead of repeating the code in every controller action - checking authentication and redirecting guests is a good example. Controllers instead contain logic unique to specific routes/actions - you could use middleware for this, but you'd need separate middleware for every route's logic and it would all get very messy.
Policies/abilities are simply a way of checking user permissions - you can query them from a controller, or from middleware, or anywhere else. They only return true or false, so they aren't equivalent to controllers or middleware. Most of the time abilities will be comparing a user to another model, which will have been loaded based on an identifier sent to a controller action, but there are probably some applications for use with middleware too.
I have asked myself the same question. In practice, I predominantly use middleware.
My most common usage is when authorisation is only allowed for a specific user, for instance:
public function update(User $user, user $model)
{
return $user->id === $model->id;
}
Though, even in the instance above, Yes, one could do without it and write their own logic in the controller to do the same thing.
I also like the before method, which I use to allow the administrator full-privileges for a model, for example:
public function before($user, $ability)
{
if ($user->admin === 1) {
return true;
}
}
The main reason, though, why I have started to use Policies on some Laravel projects is because of what you can do with blade. If you find yourself setting permissions numerous times for the same user authorisation in your blade files, for example, to show an edit button, then Policies may become very useful because you can do the following with them (and more):
#can('update', $post)
<button class="btn btn-primary">Edit Post</button>
#endcan
#cannot('create', App\Models\Post::class)
<div class="alert alert-warning">You are not allowed to create a post</div>
#endcannot
I sometimes find these Policy-referencing blade methods to be super useful, when wanting to group authorisation in one place.

Laravel dual authentication types

I am developing an application using Laravel 4, where I need to have 2 authentication types.
Type 1: Users - which are administators / back-office workers of the system.
Type 2: Customers - which are the visitors of the website who can do certain things (like purchase services) if they are authenticated.
The Type 1 Users are authenticated using username/password, so that fits nicely within the Laravel authentication model.
The Type 2 Customers will be authenticated either using OAuth style (with Google / Facebook) or manual authentication if the customer prefers. I do not want to mix the two together, so if you are authenticated as a customer I don't want the authentication filter to think you can access the admin pages, and vice-versa.
The two types will have their own tables (Users and Customers respectively). Is there a way to have a different Auth model running concurrently in some way? Or do I have to write my own thing for customers? What is the recommended approach in this scenario?
If I understand your question correctly this should set you on the right path.
You can simply set an account_level indicator in each table and wrap your admin routes in a filter that checks that the user's account_level is correct. For example:
in routes.php
Route::group(array('before' => 'admin_only'), function() {
Route::get('my-admin-route', 'AdminController#adminAction');
});
in filters.php
Route::filter('admin_only', function() {
if (!Auth::check() || Auth::user()->account_level !== Config::get('constants.ADMIN_ACCOUNT_LEVEL') {
return App::abort(404);
}
});
In order to log a user in that does not have a username and password in your system you would need to handle the OAuth connection separately and once you have a valid user you may use the Auth::login($user) method to get the user back into your usual application flow.
http://laravel.com/docs/4.2/security#manually

Laravel : ensure user can only be logged in on one computer at a time

I want to ensure that the users can't share the same login/password.
To do this, when a user try to log in i want to check if he is not already connected on a different computer.
My first idea is get all the users having actives sessions, but i don't know how ?
Or may be there is a better way ?
You have more things in here:
ensuring that the users don't share the same credentials can be done
through simple validation
checking if user is already logged in can
also be done through session - with login,logout methods that the user will trigger.
You, as developer have total power to manage users per session basis.
You can improve design with some events notification, but stateless nature of HTTP protocol gives you limited number of tools for user tracking (except Google machinery :))
What is happening on their local machines in different thing, and out of scope of Laravel app.

Categories