158 lines
5.1 KiB
PHP
158 lines
5.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use Closure;
|
|
use Illuminate\Http\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class BlockApiToolsMiddleware
|
|
{
|
|
/**
|
|
* Handle an incoming request.
|
|
*
|
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
|
*/
|
|
public function handle(Request $request, Closure $next): Response
|
|
{
|
|
// Check if API tool blocking is enabled
|
|
if (!config('api_security.block_api_tools_in_production')) {
|
|
return $next($request);
|
|
}
|
|
|
|
// Skip blocking for external API routes - they use API key authentication
|
|
if ($request->is('api/external*')) {
|
|
return $next($request);
|
|
}
|
|
|
|
// Only block in production environment
|
|
if (app()->environment('production')) {
|
|
$userAgent = strtolower($request->header('User-Agent', ''));
|
|
$clientIp = $request->ip();
|
|
|
|
// Check if request has valid API key - bypass blocking for external systems
|
|
if ($this->hasValidApiKey($request)) {
|
|
return $next($request);
|
|
}
|
|
|
|
// Check if IP is in allowed list
|
|
$allowedIps = config('api_security.allowed_ips', []);
|
|
if (!empty($allowedIps) && in_array($clientIp, $allowedIps)) {
|
|
return $next($request);
|
|
}
|
|
|
|
// Check if User-Agent is in allowed list
|
|
$allowedUserAgents = config('api_security.allowed_user_agents', []);
|
|
foreach ($allowedUserAgents as $allowedAgent) {
|
|
if (str_contains($userAgent, strtolower($allowedAgent))) {
|
|
return $next($request);
|
|
}
|
|
}
|
|
|
|
// Check if the User-Agent matches any blocked patterns
|
|
$blockedUserAgents = config('api_security.blocked_user_agents', []);
|
|
foreach ($blockedUserAgents as $blockedAgent) {
|
|
if (str_contains($userAgent, $blockedAgent)) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => config('api_security.blocked_message', 'API access is restricted in production environment. Please use the web interface.'),
|
|
'error' => 'API_TOOLS_BLOCKED'
|
|
], 403);
|
|
}
|
|
}
|
|
|
|
// Additional check for requests without proper browser User-Agent
|
|
// This catches tools that might not be in our list but don't look like browsers
|
|
if ($this->isSuspiciousUserAgent($userAgent)) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => config('api_security.blocked_message', 'API access is restricted in production environment. Please use the web interface.'),
|
|
'error' => 'API_TOOLS_BLOCKED'
|
|
], 403);
|
|
}
|
|
}
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
/**
|
|
* Check if the User-Agent looks suspicious (not a real browser)
|
|
*/
|
|
private function isSuspiciousUserAgent(string $userAgent): bool
|
|
{
|
|
$minLength = config('api_security.min_user_agent_length', 10);
|
|
|
|
// If User-Agent is empty or very short, it's suspicious
|
|
if (empty($userAgent) || strlen($userAgent) < $minLength) {
|
|
return true;
|
|
}
|
|
|
|
// Check for common browser patterns
|
|
$browserPatterns = [
|
|
'mozilla',
|
|
'chrome',
|
|
'safari',
|
|
'firefox',
|
|
'edge',
|
|
'opera',
|
|
'webkit',
|
|
'gecko',
|
|
'trident',
|
|
'msie',
|
|
];
|
|
|
|
$hasBrowserPattern = false;
|
|
foreach ($browserPatterns as $pattern) {
|
|
if (str_contains($userAgent, $pattern)) {
|
|
$hasBrowserPattern = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If no browser pattern is found, it's likely an API tool
|
|
return !$hasBrowserPattern;
|
|
}
|
|
|
|
/**
|
|
* Check if the request has a valid API key for external system access
|
|
*/
|
|
private function hasValidApiKey(Request $request): bool
|
|
{
|
|
// Check for API key in headers (X-API-Key, Authorization Bearer, or API-Key)
|
|
$apiKey = $request->header('X-API-Key')
|
|
?? $request->header('API-Key')
|
|
?? $this->extractBearerToken($request->header('Authorization'));
|
|
|
|
if (!$apiKey) {
|
|
return false;
|
|
}
|
|
|
|
// Get valid API keys from configuration
|
|
$validApiKeys = config('api_security.valid_api_keys', []);
|
|
|
|
// If no API keys configured, return false
|
|
if (empty($validApiKeys)) {
|
|
return false;
|
|
}
|
|
|
|
// Check if the provided API key is valid
|
|
return in_array($apiKey, $validApiKeys);
|
|
}
|
|
|
|
/**
|
|
* Extract Bearer token from Authorization header
|
|
*/
|
|
private function extractBearerToken(?string $authorization): ?string
|
|
{
|
|
if (!$authorization) {
|
|
return null;
|
|
}
|
|
|
|
if (preg_match('/Bearer\s+(.*)$/i', $authorization, $matches)) {
|
|
return $matches[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|