I've been using a method in Laravel Middleware that checks for strings in any URL segment to block the IP if it matches the "blacklisted" strings.
In the beginning, I had just a few strings to check, but now, the list is growing, and when I tried to optimize it to use a blacklist array
, I ended up in a complete mess in the code and in my mind.
I believe this can be done but can't figure out the best way to optimize this middleware. Below is a sample of the Middleware code with notes where I'm having trouble.
In the handle($request, Closure $next)
method is calling the $this->inUrl()
method for all the blacklisted strings.
I've tried to add a protected $blacklisted
array, to be used in the $this->inUrl()
but can't make it work.
Thank you in advance for any suggestions that would be much appreciated and welcome. I am also thinking of providing the code as a gist on GitHub when optimized.
namespace App\Http\Middleware;
/**
* Class VerifyBlacklistedRequests
*
* @package App\Http\Middleware
*/
class VerifyBlacklistedRequests
{
/**
* The array of blacklisted request string segments
*
* @access protected
* @var array|string[]
*/
protected array $blacklisted = [
'.env', '.ftpconfig', '.vscode', ',git', '.git/HEAD'
// etc...
];
/**
* Handle an incoming request.
*
* @access public
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if($this->inUrl('.env')
|| $this->inUrl('.ftpconfig')
|| $this->inUrl('.vscode')
|| $this->inUrl('.git')
|| $this->inUrl('.git/HEAD')
// many more checks below the above ones
) {
// logic that blocks the IP goes here and working fine
}
return $next($request);
}
/**
* Check if the string is in any URL segment or at the one specified.
*
* @access protected
*
* @param string|mixed $value Segment value/content.
* @param integer $segment Segment position.
*
* @return bool
*/
protected function inUrl(string $value, $segment = -1)
{
if($segment !== -1 && request()->segment($segment) === $value) {
return true;
}
collect(request()->segments())->each(function ($segment) use ($value) {
if($segment === $value) {
return true;
}
});
return false;
}
}
After all the suggestions, kindly posted here, I ended up with a solution that uses some of the suggested methods.
The result ended up by reducing the pages' loading time by more than 1 second.
My final implementation:
security.php
which contains the blacklisted request strings, and a shortlist of whitelisted IPs.The security.php config file
<?php
return [
/*
|--------------------------------------------------------------------------
| Whitelisted IPs configuration
|--------------------------------------------------------------------------
|
| These are the settings for the whitelisted IPs. The array contains
| the IPs that should not trigger the IP block.
|
*/
'whitelisted_ips' => [
// whitelisted IPs array
],
/*
|--------------------------------------------------------------------------
| Blacklisted request strings configuration
|--------------------------------------------------------------------------
|
| These are the settings for the blacklisted request strings. The array contains
| the strings that should trigger the IP to be blocked.
|
*/
'blacklisted_requests' => [
'.env',
'.ftpconfig',
'.vscode',
'.git',
'.git/HEAD',
'_profiler',
'__media__',
'administrator',
//...
];
];
inUrl()
methodThe VerifyBlacklistedRequests middleware
<?php
namespace App\Http\Middleware;
use Closure;
/**
* Class VerifyHackingAttemptsRequests
*
* @property \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed white_listed_ips
* @property \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed blacklist
* @package App\Http\Middleware
*/
class VerifyHackingAttemptsRequests
{
/**
* @access protected
* @var \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed
*/
protected $blacklist;
/**
* @access protected
* @var \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed
*/
protected $white_listed_ips;
/**
* VerifyHackingAttemptsRequests constructor
*
* @access public
*/
public function __construct()
{
$this->blacklist = config('security.blacklisted_requests');
$this->white_listed_ips = config('security.whitelisted_ips');
}
/**
* Handle an incoming request.
*
* @access public
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
* @since 2.8.1
*/
public function handle($request, Closure $next)
{
$exists = false;
foreach(request()->segments() as $segment) {
if(in_array($segment, $this->blacklist)) {
$exists = true;
}
}
if($exists) {
$this->blockIp($request)
}
return $next($request);
}
/**
* Method to save an IP in the Blocked IP database table
*
* @access protected
*
* @param \Illuminate\Http\Request $request
*
* @return \App\Models\BlockedIp
*/
protected function blockIp(Request $request, $notes = null)
{
// the logic to persist the data through the BlockedIp model
}
}
In summary, the inUrl()
method was removed, removing all the loops and method calls and, as mentioned above, the pages' loading time was sliced by more than 50%.
Thanks to all for the suggested methods which contributed to helping me solve the problem.