# Bezpieczeństwo REST API w Symfony 2026: OAuth2, Rate Limiting i Pytania Rekrutacyjne > Kompleksowy przewodnik po zabezpieczaniu REST API w Symfony z OAuth2 token introspection, rate limiting i walidacją JWT. Obejmuje funkcje bezpieczeństwa Symfony 7.3 oraz pytania rekrutacyjne. - Published: 2026-09-14 - Updated: 2026-09-14 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- Bezpieczeństwo REST API w Symfony wymaga wielowarstwowego podejścia łączącego uwierzytelnianie, autoryzację i kontrolę ruchu. Symfony 7.3 wprowadził natywne wsparcie dla OAuth2 token introspection zgodne z RFC 7662, natomiast komponent RateLimiter zapewnia wbudowaną ochronę przed nadużyciami. > **Kluczowe warstwy bezpieczeństwa dla API Symfony** > > Produkcyjne API Symfony potrzebuje trzech warstw ochrony: uwierzytelniania (kto wywołuje), autoryzacji (do czego ma dostęp) i rate limitingu (jak często). Brak którejkolwiek warstwy naraża aplikację na credential stuffing, wyciek danych lub atak denial of service. ## OAuth2 Token Introspection w Symfony 7.3 Symfony 7.3 dodaje wbudowane wsparcie dla [OAuth2 Token Introspection (RFC 7662)](https://datatracker.ietf.org/doc/html/rfc7662). Ta funkcja waliduje tokeny dostępu poprzez bezpośrednie odpytanie serwera autoryzacji, eliminując potrzebę lokalnego dekodowania tokenów. Jest to istotne gdy format tokenu jest nieprzezroczysty lub kontrolowany przez zewnętrznego dostawcę tożsamości. Konfiguracja `AccessTokenHandler` akceptuje endpoint introspection: ```yaml # config/packages/security.yaml security: firewalls: api: pattern: ^/api stateless: true access_token: token_handler: introspection: client_id: '%env(OAUTH_CLIENT_ID)%' client_secret: '%env(OAUTH_CLIENT_SECRET)%' introspection_url: '%env(OAUTH_INTROSPECTION_URL)%' ``` Odpowiedź introspection zawiera `active`, `scope`, `client_id` i opcjonalnie `username`. Symfony automatycznie mapuje te wartości na atrybuty bezpieczeństwa. ```php // src/Controller/Api/ProfileController.php namespace App\Controller\Api; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route('/api/profile', methods: ['GET'])] #[IsGranted('ROLE_USER')] class ProfileController extends AbstractController { public function __invoke(): JsonResponse { // Token już zwalidowany przez introspection $user = $this->getUser(); return $this->json([ 'id' => $user->getId(), 'email' => $user->getEmail(), 'scopes' => $user->getRoles(), ]); } } ``` To przenosi ciężar weryfikacji podpisu JWT z aplikacji na serwer autoryzacji. Serwer autoryzacji zajmuje się rotacją kluczy, unieważnianiem tokenów i walidacją zakresów. ## Implementacja Rate Limiting z komponentem RateLimiter [Komponent RateLimiter](https://symfony.com/doc/current/rate_limiter.html) chroni endpointy przed nadużyciami używając algorytmów token bucket lub sliding window. Konfiguracja odbywa się w `framework.yaml`: ```yaml # config/packages/framework.yaml framework: rate_limiter: # Ogólny limit API: 100 żądań na minutę api_limiter: policy: sliding_window limit: 100 interval: '1 minute' # Surowszy limit dla endpointów uwierzytelniania login_limiter: policy: token_bucket limit: 5 rate: { interval: '1 minute', amount: 5 } ``` Rate limiting można zastosować do kontrolerów za pomocą event subscribera: ```php // src/EventSubscriber/RateLimitSubscriber.php namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\RateLimiter\RateLimiterFactory; final class RateLimitSubscriber implements EventSubscriberInterface { public function __construct( private readonly RateLimiterFactory $apiLimiter, ) {} public static function getSubscribedEvents(): array { return [KernelEvents::REQUEST => ['onRequest', 10]]; } public function onRequest(RequestEvent $event): void { if (!$event->isMainRequest()) { return; } $request = $event->getRequest(); // Zastosuj tylko do tras API if (!str_starts_with($request->getPathInfo(), '/api')) { return; } // Użyj IP klienta lub uwierzytelnionego użytkownika jako klucza limitera $key = $request->getClientIp(); $limiter = $this->apiLimiter->create($key); if (!$limiter->consume()->isAccepted()) { throw new TooManyRequestsHttpException(); } } } ``` Dla uwierzytelnionych API warto zastąpić klucz oparty na IP identyfikatorem użytkownika, aby zapobiec wpływowi pojedynczego nadużywającego użytkownika na legalny ruch z tej samej sieci. ## Walidacja JWT bez zewnętrznych zależności Gdy serwer autoryzacji wydaje JWT ze znanym kluczem publicznym, Symfony może walidować tokeny lokalnie używając `OidcUserInfoTokenHandler`: ```yaml # config/packages/security.yaml security: firewalls: api: pattern: ^/api stateless: true access_token: token_handler: oidc_user_info: base_uri: '%env(OIDC_ISSUER)%' claim: email ``` Dla własnych JWT bez dostawcy OIDC można użyć `lexik/jwt-authentication-bundle`: ```php // src/Security/JwtTokenAuthenticator.php namespace App\Security; use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; final class JwtTokenAuthenticator implements AccessTokenHandlerInterface { public function __construct( private readonly JWTTokenManagerInterface $jwtManager, ) {} public function getUserBadgeFrom(string $accessToken): UserBadge { // Automatycznie dekoduje i waliduje podpis $payload = $this->jwtManager->parse($accessToken); return new UserBadge($payload['sub']); } } ``` Bundle JWT obsługuje weryfikację podpisu RS256/ES256, sprawdzanie wygaśnięcia i walidację wystawcy. Klucz publiczny należy przechowywać w `config/jwt/public.pem` i odwoływać się do niego w `lexik_jwt_authentication.yaml`. ## Zabezpieczanie endpointów API za pomocą Voterów Symfony Voters zapewniają szczegółową autoryzację wykraczającą poza proste sprawdzanie ról. Typowy wzorzec sprawdza własność zasobu: ```php // src/Security/Voter/ArticleVoter.php namespace App\Security\Voter; use App\Entity\Article; use App\Entity\User; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; final class ArticleVoter extends Voter { public const EDIT = 'ARTICLE_EDIT'; public const DELETE = 'ARTICLE_DELETE'; protected function supports(string $attribute, mixed $subject): bool { return in_array($attribute, [self::EDIT, self::DELETE], true) && $subject instanceof Article; } protected function voteOnAttribute( string $attribute, mixed $subject, TokenInterface $token ): bool { $user = $token->getUser(); if (!$user instanceof User) { return false; } /** @var Article $article */ $article = $subject; // Administratorzy mogą wszystko if (in_array('ROLE_ADMIN', $user->getRoles(), true)) { return true; } // Autorzy mogą edytować/usuwać własne artykuły return $article->getAuthor() === $user; } } ``` Użycie votera w kontrolerach: ```php #[Route('/api/articles/{id}', methods: ['PUT'])] public function update(Article $article, Request $request): JsonResponse { $this->denyAccessUnlessGranted(ArticleVoter::EDIT, $article); // Logika aktualizacji } ``` Votery centralizują logikę autoryzacji i czynią ją testowalną. Często pojawiają się również w [pytaniach rekrutacyjnych dotyczących Symfony](/technologies/symfony/interview-questions/events-subscribers) o komponent bezpieczeństwa. ## Typowe podatności API i sposoby ich eliminacji [OWASP API Security Top 10](https://owasp.org/API-Security/editions/2023/en/0x11-t10/) identyfikuje powtarzające się podatności w API. Symfony zapewnia wbudowaną ochronę przed wieloma z nich: | Podatność | Ochrona w Symfony | |-----------|-------------------| | Broken Object Level Authorization | Votery ze sprawdzaniem własności | | Broken Authentication | Throttling logowania, bezpieczne hashowanie haseł | | Excessive Data Exposure | Grupy serializacji DTO | | Lack of Rate Limiting | Komponent RateLimiter | | Mass Assignment | Walidacja formularzy, mapowanie DTO | | Security Misconfiguration | Symfony security checker, zmienne środowiskowe | Dla ochrony przed mass assignment nigdy nie należy hydratować encji bezpośrednio z danych żądania: ```php // src/Dto/CreateArticleDto.php namespace App\Dto; use Symfony\Component\Validator\Constraints as Assert; final class CreateArticleDto { public function __construct( #[Assert\NotBlank] #[Assert\Length(max: 255)] public readonly string $title, #[Assert\NotBlank] public readonly string $content, // Celowo pominięte: author, createdAt, status // Te wartości są ustawiane przez aplikację, nie przez klienta ) {} } ``` Podejście z białą listą DTO zapobiega ustawianiu przez klientów pól, których nie powinni kontrolować, takich jak `isAdmin` czy `createdAt`. ## Konfiguracja CORS dla konsumentów API Nagłówki Cross-Origin Resource Sharing kontrolują, które domeny mogą wywoływać API z przeglądarek. Bundle `nelmio/cors-bundle` zapewnia deklaratywną konfigurację: ```yaml # config/packages/nelmio_cors.yaml nelmio_cors: defaults: allow_origin: ['%env(CORS_ALLOW_ORIGIN)%'] allow_methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] allow_headers: ['Content-Type', 'Authorization'] max_age: 3600 paths: '^/api/': origin_regex: true allow_origin: ['^https://.*\.example\.com$'] allow_credentials: true ``` Należy unikać `allow_origin: ['*']` w połączeniu z `allow_credentials: true`. Ta kombinacja naraża API na kradzież poświadczeń przez złośliwe strony. Lepiej używać jawnych białych list domen lub wzorców regex. ## Pytania techniczne na rozmowach o bezpieczeństwie API Symfony Te pytania często pojawiają się na rozmowach rekrutacyjnych dla starszych developerów Symfony. Odpowiedzi odzwierciedlają możliwości Symfony 7.3. **P: Jak Symfony obsługuje walidację tokenów dostępu OAuth2?** Symfony 7.3 wspiera trzy podejścia: lokalną walidację JWT z weryfikacją podpisu, wywołania endpointu OIDC user info oraz [RFC 7662 token introspection](https://symfony.com/blog/new-in-symfony-7-3-security-improvements). Introspection sprawdza się dla nieprzezroczystych tokenów lub scenariuszy, gdy aplikacja nie kontroluje serwera autoryzacji. `AccessTokenHandler` abstrahuje wszystkie trzy za ujednoliconym interfejsem. **P: Jaka jest różnica między firewallami a access control w Symfony?** Firewalle definiują mechanizmy uwierzytelniania dla wzorców URL. Reguły access control definiują wymagania autoryzacji po pomyślnym uwierzytelnieniu. Firewall może wymagać ważnego JWT, podczas gdy access control wymaga `ROLE_ADMIN` dla `/api/admin/*`. Działają sekwencyjnie: firewall uwierzytelnia, następnie access control autoryzuje. **P: Jak zapobiec atakom brute force na endpoint logowania?** Wbudowany login throttling w Symfony ogranicza nieudane próby per nazwa użytkownika i IP. Konfiguracja `login_throttling` w firewallu: ```yaml security: firewalls: main: login_throttling: max_attempts: 5 interval: '15 minutes' ``` Dla uwierzytelniania API należy połączyć z komponentem RateLimiter na endpoincie tokenów. Liczniki prób warto przechowywać w Redis dla wdrożeń wieloinstancyjnych. **P: Wyjaśnij Symfony Voters i kiedy ich używać zamiast prostych sprawdzeń ról.** Votery implementują złożoną logikę autoryzacji zależną od zasobu, nie tylko od roli użytkownika. Należy używać voterów gdy: użytkownik musi być właścicielem zasobu, zasób ma maszynę stanów (draft vs opublikowany), lub autoryzacja zależy od reguł biznesowych (poziom subskrypcji). Sprawdzanie ról wystarcza dla statycznych uprawnień jak "tylko administratorzy mają dostęp do ustawień." Więcej pytań o bezpieczeństwo Symfony znajduje się w [przewodniku przygotowania do rozmowy Symfony](/blog/symfony/symfony-interview-questions). ## Budowanie bezpiecznego API Symfony: Kluczowe wnioski - Skonfiguruj OAuth2 token introspection dla zewnętrznych dostawców tożsamości gdy format tokenu jest nieprzezroczysty - Stosuj rate limiting na poziomie infrastruktury (reverse proxy) i aplikacji (komponent RateLimiter) dla obrony w głąb - Używaj Voterów dla autoryzacji na poziomie zasobów, rezerwując sprawdzanie ról dla statycznych uprawnień - Mapuj dane żądań na DTO z jawnymi właściwościami aby zapobiec mass assignment - Przechowuj sekrety w zmiennych środowiskowych, nigdy w plikach `config/*.yaml` commitowanych do kontroli wersji - Testuj reguły bezpieczeństwa testami funkcjonalnymi `WebTestCase` weryfikującymi zarówno dozwolony jak i zabroniony dostęp - Audytuj zależności za pomocą `symfony security:check` w pipeline'ach CI --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/symfony/symfony-rest-api-security-oauth2-rate-limiting-2026