Bezpečnost – Public API a Middleware
Veřejné Endpointy (Public API)
Veřejné endpointy jsou určeny pro JavaScript frontend a prochází middleware pipelinem s bezpečnostními kontrolami.
Registrace Public Endpointu
Public endpointy se registrují v config/data.yaml:
# config/data.yaml
publicEndpoints:
- CookiesBar/updateLog
- Form/submit
- Newsletter/subscribe
Pouze endpointy v tomto whitelist projdou middleware. Všechny ostatní vrátí 403.
Bezpečnostní Kontroly
Middleware v app/Middlewares/Restriction/publicEndpointsMiddleware.php kontroluje:
- Whitelist firewall - Pouze endpointy v
config/data.yamljsou povoleny - CSRF token - Povinný (
csrfquery param nebo POST) - Rate limiting - Max 20 requestů za 60 sekund na IP
- Referer check - Validace origin (volitelná)
Všechny pokusy o přístup jsou logovány do var/log/security.log.
Volání Public Endpointu
// 1. Příprava CSRF tokenu
const csrfToken = document.querySelector('[data-csrf]').dataset.csrf;
// 2. POST na public endpoint s CSRF
fetch('/getData/CookiesBar/updateLog?csrf=' + encodeURIComponent(csrfToken), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ oldToken: 'value' })
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => {
if (error.status === 403) {
console.error('CSRF token invalid or rate limit exceeded');
}
});
CSRF Ochrana
CSRF token musí být součástí každého veřejného requestu:
// CSRF z data atributu v HTML
<div data-csrf="<?= Session::get('frontend_csrf') ?>"></div>
// JS
const csrfToken = document.querySelector('[data-csrf]').dataset.csrf;
fetch('/getData/CookiesBar/updateLog?csrf=' + encodeURIComponent(csrfToken));
Nebo jako POST data:
fetch('/getData/CookiesBar/updateLog', {
method: 'POST',
body: JSON.stringify({ csrf: csrfToken, data: '...' })
});
Rate Limiting
Public endpointy jsou chráněny rate limitingem:
- Max: 20 requestů
- Per: 60 sekund
- Per IP: Individuální limit pro každou IP adresu
Pokud limit překročíte, vrátí 429 Too Many Requests.
// Příliš rychlé requesty = 429
for (let i = 0; i < 25; i++) {
fetch('/getData/CookiesBar/updateLog?csrf=...');
}
// Posledních 5 requestů = 429 Too Many Requests
IP Filtrování a CORS
Přístup je kontrolován dle nastavení v .env:
ALLOWED_IP=127.0.0.1,::1,93.185.102.4
CORS_ORIGINS=
ALLOWED_IP- IPs povolené pro cron/admin-only endpointyCORS_ORIGINS- CORS origins (prázdné = všem)
Admin Endpointy (bez Public API)
Admin a interní endpointy (bez _ prefixu) NEJSOU v whitelist a volají se přímý require z PHP:
// Admin - žádná ochrana (interní volání)
$output = Data\get('News/List');
// Frontend tagy - žádná ochrana (interní volání)
$output = Data\post('News/_latestThree', $data);
// CSRF a Rate Limit se NE aplikují - jsou to přímé PHP volání
Bezpečnostní Logování
Všechny pokusy o přístup jsou logovány:
Logger::setLog('security');
Logger::error('Unauthorized data endpoint access', [
'ip' => $clientIp,
'path' => $path,
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
]);
Logy jsou v var/log/security.log:
[2024-01-18 10:30:45] ERROR: Unauthorized data endpoint access - {"ip":"192.168.1.1","path":"/getData/News/Secret"}
[2024-01-18 10:31:10] ERROR: Rate limit exceeded - {"ip":"93.185.102.4","endpoint":"CookiesBar/updateLog","requests":25}
[2024-01-18 10:32:15] ERROR: Invalid CSRF token - {"ip":"10.0.0.5","endpoint":"CookiesBar/updateLog"}
Shrnutí
| Typ | Volání | Middleware | CSRF | RateLimit | Logging |
|---|---|---|---|---|---|
| Admin PHP | Přímý require | Ne | Ne | Ne | Ne |
| Frontend tagy | Přímý require | Ne | Ne | Ne | Ne |
| Public API (JS) | HTTP fetch | Ano (whitelist) | Ano | Ano (20/60) | Ano |