Files
My-KOPKB/be/app/Http/Middleware/BlockApiToolsMiddleware.php
T
ISMAIL MASSERAN 94ecbe5887 first init
2026-06-08 11:37:14 +08:00

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;
}
}