Prečo tradičná ochrana nestačí
Klasické riešenia ako robots.txt a CAPTCHA chránili weby pred starými generáciami crawlerov. API endpointy sú iná situácia: odpovedajú strojovo čitateľnými dátami (JSON/XML) bez vizuálneho rozhrania, takže CAPTCHA nie je použiteľná. Súbor robots.txt je neformálna dohoda — bot ho môže jednoducho ignorovať a zákon mu v tom nezabráni. AI crawlery (GPTBot, ClaudeBot, PerplexityBot, Bytespider, CCBot) navyše pristupujú k endpointom priamo cez HTTP bez akejkoľvek autentifikácie. Ochrana API musí byť aktívna, nie pasívna.
Efektívna ochrana sa skladá z niekoľkých vrstiev, ktoré sa vzájomne dopĺňajú:
- Rate limiting — obmedzenie počtu požiadaviek za čas
- Autentifikácia — overenie totožnosti klienta
- Detekcia botov — identifikácia podľa User-Agent a správania
- Sieťová vrstva (Cloudflare) — blokovanie ešte pred serverom
- Honeypot endpointy — pasca na automatizované skenery
- Logovanie — viditeľnosť do toho, čo sa deje
Rate limiting v Laraveli
Rate limiting je prvá a najdôležitejšia vrstva. Laravel od verzie 8 ponúka RateLimiter facade, ktorý umožňuje definovať vlastné limity pre API endpointy priamo v kóde.
Vlastný limiter pre API
V súbore app/Providers/AppServiceProvider.php (alebo RouteServiceProvider.php) definujte limiter:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('api', function (Request $request) {
return $request->user()
? Limit::perMinute(120)->by($request->user()->id)
: Limit::perMinute(30)->by($request->ip());
});
RateLimiter::for('ai-sensitive', function (Request $request) {
return Limit::perHour(10)->by($request->ip())
->response(function () {
return response()->json([
'error' => 'Prekročený limit požiadaviek.',
'retry_after' => 3600,
], 429);
});
});
V routes súbore priraďte middleware k endpointom:
Route::middleware(['throttle:api'])->group(function () {
Route::get('/products', [ProductController::class, 'index']);
Route::get('/products/{id}', [ProductController::class, 'show']);
});
Route::middleware(['throttle:ai-sensitive'])->group(function () {
Route::get('/export/all', [ExportController::class, 'all']);
});
CACHE_STORE=redis v .env.
Rate limiting v Nginxe (pred PHP)
Nginx dokáže obmedziť požiadavky ešte pred tým, ako sa dostanú k PHP — nulové zaťaženie PHP-FPM pri útoku:
http {
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/m;
server {
location /api/ {
limit_req zone=api_limit burst=10 nodelay;
limit_req_status 429;
try_files $uri $uri/ /index.php?$query_string;
}
}
}
Kombinujte Nginx rate limiting s Laravelom: Nginx zastaví hrubé útoky, Laravel spravuje jemnozrnné limity podľa používateľa alebo API kľúča.
Blokovanie AI crawlerov podľa User-Agent
AI crawlery sa vo väčšine prípadov identifikujú vlastným User-Agent reťazcom — GPTBot, ClaudeBot, PerplexityBot a ďalšie. Blokovanie podľa User-Agent je prvá rýchla vrstva ochrany, aj keď nie je neprekonateľná (bot môže User-Agent falšovať).
Middleware pre blokovanie botov v Laraveli
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class BlockAiCrawlers
{
private const BLOCKED_AGENTS = [
'gptbot', 'chatgpt-user', 'claudebot', 'claude-web',
'perplexitybot', 'bytespider', 'ccbot', 'amazonbot',
'anthropic-ai', 'cohere-ai', 'diffbot', 'omgili',
'facebookexternalhit',
];
public function handle(Request $request, Closure $next): mixed
{
$userAgent = strtolower($request->userAgent() ?? '');
foreach (self::BLOCKED_AGENTS as $blocked) {
if (str_contains($userAgent, $blocked)) {
return response()->json([
'error' => 'Automated access is not permitted.',
], 403);
}
}
return $next($request);
}
}
Zaregistrujte middleware v bootstrap/app.php (Laravel 11+) a aplikujte na API routes:
Route::middleware(['throttle:api', \App\Http\Middleware\BlockAiCrawlers::class])
->prefix('api')
->group(base_path('routes/api.php'));
Cloudflare WAF: blokovanie pred serverom
Cloudflare stojí pred vaším serverom a môže blokovať boty ešte pred tým, ako sa požiadavka dostane k Nginxu alebo PHP. Pre API endpointy odporúčam dve pravidlá.
Pravidlo 1: blokovanie známych AI crawlerov
V Cloudflare dashboarde pod Security → WAF → Custom rules vytvorte pravidlo:
(http.user_agent contains "GPTBot") or
(http.user_agent contains "ClaudeBot") or
(http.user_agent contains "PerplexityBot") or
(http.user_agent contains "Bytespider") or
(http.user_agent contains "CCBot") or
(http.user_agent contains "anthropic-ai")
Akcia: Block
Pravidlo 2: Managed Challenge pre podozrivé požiadavky na API
Pre citlivé endpointy, kde boty nemajú čo hľadať, ale legítni klienti áno:
(http.request.uri.path matches "^/api/export") and
(not cf.client.bot) and
(not ip.src in $trusted_ips)
Akcia: Managed Challenge
Managed Challenge od Cloudflare je nenápadný — pre skutočného používateľa (prehliadač) beží na pozadí, bot ho nevyrieši.
Rate limiting v Cloudflare
Cloudflare Rate Limiting (Security → Rate Limiting) pridá ďalšiu vrstvu pred serverom — napríklad max. 100 požiadaviek za 10 sekúnd z jednej IP na /api/*. Efektívne pri DDoS útokoch, kde ani Nginx nestíha.
API autentifikácia a IP allowlisting
Verejné API bez akejkoľvek autentifikácie je pozvánka pre scrapery. Aj minimálna autentifikácia výrazne zredukuje automatizovaný prístup.
API tokeny (Bearer auth)
Laravel Sanctum vydáva tokeny pre každého klienta — každý prístup je spätne dohľadateľný:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens;
}
// Vydanie tokenu
$token = $user->createToken('client-app', ['read:products'])->plainTextToken;
// Overenie v middleware
Route::middleware('auth:sanctum')->get('/products', ...);
IP allowlisting pre B2B integrácie
Pre interné systémy alebo B2B partnerov, kde je IP adresa stabilná, pridajte IP allowlist ako ďalšiu vrstvu:
class IpAllowlist
{
private const ALLOWED = ['203.0.113.10', '198.51.100.0/24'];
public function handle(Request $request, Closure $next): mixed
{
foreach (self::ALLOWED as $range) {
if ($this->ipInRange($request->ip(), $range)) {
return $next($request);
}
}
return response()->json(['error' => 'Forbidden'], 403);
}
private function ipInRange(string $ip, string $range): bool
{
if (!str_contains($range, '/')) {
return $ip === $range;
}
[$subnet, $bits] = explode('/', $range);
return (ip2long($ip) >> (32 - (int)$bits)) === (ip2long($subnet) >> (32 - (int)$bits));
}
}
Prečo robots.txt nechráni API
robots.txt je neformálna dohoda, nie technická bariéra. Pravidlo Disallow: /api/ komunikuje zámer, ale nevynucuje ho — HTTP server odpovedá na každú požiadavku bez ohľadu na obsah robots.txt. Boty, ktoré chcú scrapeovať, jednoducho tento súbor ignorujú. Napriek tomu ho nevynechávajte: legitímne vyhľadávače ako Googlebot ho rešpektujú, čo šetrí crawl budget pre dôležitejšie stránky.
/api/ v robots.txt ako Disallow, takže sme chránení." — Nie ste. robots.txt nechráni API. Vyžaduje sa technická vrstva ochrany.
Honeypot endpointy
Honeypot endpoint je falošná „pasca" — URL, ktorá nevyzerá legitímne pre človeka, ale automatizovaný skener ju navštívi, pretože prehľadáva všetky adresy. Akákoľvek požiadavka na honeypot endpoint automaticky zaradí IP adresu na čiernu listinu.
Route::any('/api/internal/debug', function (Request $request) {
$ip = $request->ip();
$ua = $request->userAgent();
Log::channel('security')->warning('Honeypot hit', [
'ip' => $ip,
'user_agent' => $ua,
'url' => $request->fullUrl(),
]);
cache()->put("blocked_ip:{$ip}", true, now()->addHours(24));
return response()->json(['error' => 'Not Found'], 404);
});
Middleware pre kontrolu čiernej listiny IP adries:
public function handle(Request $request, Closure $next): mixed
{
if (cache()->has("blocked_ip:{$request->ip()}")) {
return response()->json(['error' => 'Forbidden'], 403);
}
return $next($request);
}
Pridajte niekoľko honeypot URL adries, ktoré vyzerajú lákavo pre scrapery: /api/v1/admin/users, /api/dump, /api/export/full. Skutočné endpointy dokumentujte — len legitímni klienti, ktorí čítajú dokumentáciu, ich budú vedieť obísť.
Logovanie podozrivých vzorov
Bez logovania ste slepí — neviete, koľko botov pristupuje k API ani odkiaľ prichádzajú. Minimálny logging pre bezpečnostný audit:
class ApiSecurityLogger
{
public function logSuspicious(Request $request, string $reason): void
{
Log::channel('security')->warning('Suspicious API request', [
'reason' => $reason,
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
'method' => $request->method(),
'url' => $request->path(),
'rate_limit_remaining' => $request->header('X-RateLimit-Remaining'),
]);
}
}
Čo logovať:
- Každý hit honeypot endpointu
- Požiadavky s
User-Agentznámeho bota (aj keď ich nepustíte ďalej) - Všetky odpovede 429 (Too Many Requests)
- Požiadavky bez
User-Agenthlavičky (takmer vždy bot alebo skript) - Neobvyklé vzory: desiatky rôznych endpointov z jednej IP za krátky čas
security nakonfigurujte v config/logging.php so separátnym súborom, napríklad storage/logs/security.log.
llms.txt a dobrovoľné vymedzenie pre AI
Súbor /llms.txt v roote domény je vznikajúci štandard (analogický ku robots.txt), ktorý hovorí AI systémom, čo môžu použiť na trénovanie a čo nie. Pridáva sa ako doplnok k technickým opatreniam — väčšina eticky spravovaných AI crawlerov ho bude rešpektovať. Technickú ochranu však nenahradí.
Záver: desaťbodový checklist
- Rate limiting nasadený v Laraveli (rozdielne limity pre autentifikovaných a anonymných klientov)
- Rate limiting v Nginxe ako záchranná sieť pri obchádzaní PHP
- Middleware blokuje API klientov so známymi AI crawler User-Agent reťazcami
- Cloudflare WAF pravidlo blokuje GPTBot, ClaudeBot, PerplexityBot a ďalšie
- Citlivé endpointy vyžadujú autentifikáciu (Sanctum token alebo API kľúč)
- B2B integrácie sú ďalej chránené IP allowlistom
- Nasadené aspoň 3 honeypot endpointy s automatickým 24-hodinovým banom IP
robots.txtobsahujeDisallow: /api/pre legitímne crawlery- Bezpečnostné udalosti (429, honeypot hity, blokované boty) sa logujú do separátneho kanála
- Alerting pri zvýšenej aktivite (napr. >50 zablokovaných požiadaviek za hodinu)