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

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.

Related

What would be a proper way to handle tokens in monolith application?

I have a monolith web application powered by Laravel. Users access different forms and some of them have button on them that executes Ajax call to the back-end (example relative endpoint: api/external/get-current-temperature). A back-end function that handles the request than connects to an external service via API and obtain data, writes some log in database and pass data back to requestor (front-end user). But in order to execute any API call it has to authenticate and obtain a Token.
Question:
I have multiple users that can potentially request api/external/get-current-temperature at the same time. How should I handle authorization/token? Should I store it in database and check its expiration time before requesting a new one or what? How would I refresh it? - The external provide has no specific function that could be utilized to verify token. But I know for sure the token is valid 60 minutes.
The users of your application never have to be mixed up / mistaken with your foreign API. You can and should provide you own mechanism (i.e. tokens) to authenticate any users. If users are authenticated the external API is used, else an error-message could be provided by your application.
As users also fill several different form it's quite possible that you save some user-data. If every user has own authentication credentials it's easy and much more secure to provide only the user's own data. If you use for every user the same authentication token in your own application you might get the situation that one user can see data from another user.
So see it like this:
You / your application is the user of the external API, therefore you need only one authenticqation token for it. Your application users use the external API as a service and as that you should provide it in your app. The data though that are provided to the service might differ from user to user.
Example payment application:
The API is always the same, you as developer get an API key, but the payments are for every user of your application differently. As developer you might never even able to see, store or track the user-data that are exchanged between the foreign service and the user, but your app serves as hub and provides perhaps also some products or services that are considered in any payments.

Laravel app interacting with a 3rd party API to get a token

I have one Laravel app with a GUI where the user logs in based on the data from a MySQL database.
When the user logs in, the server needs to make a request to a specific endpoint of a 3rd party API in order to get a token. This token comes in the response of that request and, since it's some kind of a session token, it renews from time to time (which implies that this same request which retrieves the token should be called if a particular error is thrown).
In some specific views / routes the associated logic in the controller implies a request to one or more endpoints of that 3rd party API with the previsouly acquired token in the body or in the headers - depending on the endpoint.
I'm mostly concerned if someone gets access to that particular token. If that happens, then they could interact with the 3rd party API and do an unwanted mess. So I'm ok if the pages or operations take a little longer as long as the implemented procedure is very secure (the risk of the previous scenario to happen be extremely low).
What's the procedure I should aim for? The desired answer would take advantage of Laravel "machineries" and refer where and how this token should be stored.
In Web Development this scenario usually handles with CSRF token, to ensure the Right user has sending The Request.
from your question i assumed that:
your front-end sends request to third-party Api.
if your third-party library supports CSRF Protection
My Recommendation is to use an Proxy Design Pattern:
Front-end invoke a route in our back-end.
your back-end route (plays proxy role) requests third-party library with session("third_party_session_token")
Third-party only Responses your back-end.
Back-end return response to front-end.
So in this way, The Third-lib Token Will remain only in Back-end.
Third-party Api-tokens are stored in users session space .
you can use laravel Encryption, if you are worry from session data leakage:
session->put("third_party_api_token",Crypt::encryptString($api_token));
and retrieve it when you want to whitin third-party:
$api_token = Crypt::decryptString(session()->get("third_party_api_token"));
before Encrypting anything you have to generate a key using:
php artisan key:generate

Proper way to route vue/ajax requests in laravel?

I'm new to laravel and making a web service that can function without javascript (if a user has it disabled or something.)
But it would be a better user experience to be able to perform certain actions without refreshing the whole page. I'd like to be able to say, send a form without reloading the page, or refresh notifications.
The options I can think of are:
1) Send the ajax to the same route as the pure html form, but with an extra variable and make my laravel respond with json when that variable is detected
2) Use the API route? Will this detect the currently logged in user?
3) Make new routes for everything ajax, even though they function the same as my current routes (aside from returning a view)
Also, does the CSRF token work multiple times in a row, or do I need to disable that to handle multiple ajax form posts in a row without page refreshes?
I recommend keeping the routes separate, both to prevent weird caching bugs and for your own sanity as the code changes over time.
Laravel is set up out of the box to let you define web routes in routes/web.php and api routes in routes/api.php. Routes defined in your api.php file will be available at /api/* by default. It's much easier to manage changing the application this way, rather than trying to make your controllers do both views and api responses.
With Laravel Passport, your API routes can detect the currently logged in user via the auth:api middleware when combined with adding the Laravel\Passport\Http\Middleware\CreateFreshApiToken to your web middleware group.
https://laravel.com/docs/5.7/passport#consuming-your-api-with-javascript
An easy way to manage the duplicated controllers (one for web and one for api) is to put Api controllers in their own namespace, with php artisan make:controller Api/FooController. You can even set up your Api routes to look for controllers in this namespace by default by editing RouteServiceProvider.php.

how to make POST action from another server - Laravel

How can i make post request from another server to my laravel server?
I have a website from another provider (lets say domainA.com) , they have CMS system, so I can make my custom pages - the question is, I want to make a form in domainA.com, and post it to domainB.com (my original Server), how can I make it in laravel? As far as I understand I should use api route file for this, is it secure to make such a POST request? because as far as I understand there is no token protection on api requests right?
sorry for my english - i am most interested in security side of such a action - if you show me an example, it would be appreciated.
Laravel 5.4 has 2 route groups: web and api
the web group is used for all requests that come from the current laravel application. Laravel uses a csrf token with every request to make sure every request is coming from the own page to prevent cross site scripting.
the api group is for requests that a fired from an external server. For this group the csrf protection is disabled.
Remember: csrf protection ONLY checks if the requests is from your site, it does not handle the authentication or authorization.
To secure your API you can use json web tokens (jwt). There is a package that will handle the authentication parts for APIs.
If you want to keep it really simple you can write a middleware for all api calls, that is checking if the requests has a special value (your personal token) to give access to the api.
It's possible to accept post request to a Laravel Route and you can define route any of web.php or api.php route file but below are the differences.
web.php
Routes in Web.php will prevent the form without CSRF Token.
to avoid that you can add the route in VerifyCsrfToken.php file in except Array.
api.php
Routes will work directly but the api URL will be Example.com/api/<route>.
But for security you can share an Access Token for the routes and in the controller you can verify the requests with the access token and allow post.
You are right is not sure about this communication.
What you can do is a chain token code
Start with a code and every time you contact the server b it will give you a new code that you will need to use for the next message.
I know it's not as beautiful as a solution but I do not think of anything else.
You could implement your api framework but you would spend a lot of time

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.
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

Categories