Seguranca de API REST no Symfony 2026: OAuth2, Rate Limiting e Perguntas de Entrevista

Guia completo sobre seguranca de API REST no Symfony com OAuth2, rate limiting, JWT e Voters. Inclui perguntas de entrevista tecnica.

Seguranca de API REST no Symfony 2026: OAuth2, Rate Limiting e Perguntas de Entrevista

A seguranca de APIs REST no Symfony requer uma abordagem em camadas que combina autenticacao, autorizacao e controle de trafego. O Symfony 7.3 introduz suporte nativo para introspection de tokens OAuth2 via RFC 7662, enquanto o componente RateLimiter oferece protecao integrada contra abusos.

Tres camadas de seguranca para APIs Symfony

Uma API Symfony pronta para producao precisa de tres defesas: autenticacao (quem esta chamando), autorizacao (o que pode acessar) e rate limiting (com que frequencia). A ausencia de qualquer camada expoe a aplicacao a credential stuffing, exfiltracao de dados ou negacao de servico.

Introspection de Tokens OAuth2 no Symfony 7.3

O Symfony 7.3 adiciona suporte nativo para introspection de tokens OAuth2 (RFC 7662). Essa funcionalidade valida tokens de acesso consultando diretamente o servidor de autorizacao, eliminando a necessidade de decodificar tokens localmente. Essa abordagem e particularmente util quando o formato do token e opaco ou controlado por um provedor de identidade externo.

A configuracao do AccessTokenHandler aceita um endpoint de 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)%'

A resposta de introspection contem active, scope, client_id e opcionalmente username. O Symfony mapeia esses valores automaticamente para os atributos de seguranca.

src/Controller/Api/ProfileController.phpphp
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 ja validado via introspection
        $user = $this->getUser();
        
        return $this->json([
            'id' => $user->getId(),
            'email' => $user->getEmail(),
            'scopes' => $user->getRoles(),
        ]);
    }
}

Essa abordagem libera a aplicacao da verificacao de assinaturas JWT. O servidor de autorizacao gerencia a rotacao de chaves, revogacao de tokens e validacao de scopes.

Implementacao de Rate Limiting com o Componente RateLimiter

O componente RateLimiter protege os endpoints contra abusos utilizando algoritmos token bucket ou sliding window. A configuracao e feita no framework.yaml:

yaml
# config/packages/framework.yaml
framework:
    rate_limiter:
        # Limite geral da API: 100 requests por minuto
        api_limiter:
            policy: sliding_window
            limit: 100
            interval: '1 minute'
            
        # Limite mais restrito para endpoints de autenticacao
        login_limiter:
            policy: token_bucket
            limit: 5
            rate: { interval: '1 minute', amount: 5 }

O rate limiting e aplicado aos controladores atraves de um event subscriber:

src/EventSubscriber/RateLimitSubscriber.phpphp
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();
        
        // Aplicar apenas as rotas de API
        if (!str_starts_with($request->getPathInfo(), '/api')) {
            return;
        }
        
        // Usar IP do cliente ou usuario autenticado como chave
        $key = $request->getClientIp();
        $limiter = $this->apiLimiter->create($key);
        
        if (!$limiter->consume()->isAccepted()) {
            throw new TooManyRequestsHttpException();
        }
    }
}

Para APIs autenticadas, e recomendavel substituir a chave baseada em IP pelo identificador do usuario para evitar que um usuario abusivo afete o trafego legitimo proveniente da mesma rede.

Validacao JWT Sem Dependencias Externas

Quando o servidor de autorizacao emite JWTs com uma chave publica conhecida, o Symfony pode validar tokens localmente usando 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

Para JWTs auto-emitidos sem provedor OIDC, o bundle lexik/jwt-authentication-bundle oferece uma solucao robusta:

src/Security/JwtTokenAuthenticator.phpphp
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
    {
        // Decodifica e valida a assinatura automaticamente
        $payload = $this->jwtManager->parse($accessToken);
        
        return new UserBadge($payload['sub']);
    }
}

O bundle JWT gerencia a verificacao de assinaturas RS256/ES256, controles de expiracao e validacao do emissor. A chave publica e armazenada em config/jwt/public.pem e referenciada em lexik_jwt_authentication.yaml.

Pronto para mandar bem nas entrevistas de Symfony?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Seguranca de Endpoints de API com Voters

Os Voters do Symfony fornecem autorizacao granular alem de simples verificacoes de roles. Um padrao comum verifica a propriedade do recurso:

src/Security/Voter/ArticleVoter.phpphp
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;
        
        // Admins podem fazer tudo
        if (in_array('ROLE_ADMIN', $user->getRoles(), true)) {
            return true;
        }
        
        // Autores podem editar/deletar seus proprios artigos
        return $article->getAuthor() === $user;
    }
}

O uso do voter em controladores e feito assim:

php
#[Route('/api/articles/{id}', methods: ['PUT'])]
public function update(Article $article, Request $request): JsonResponse
{
    $this->denyAccessUnlessGranted(ArticleVoter::EDIT, $article);
    
    // Logica de atualizacao aqui
}

Os Voters centralizam a logica de autorizacao e a tornam testavel. Eles aparecem frequentemente nas perguntas de entrevista Symfony sobre o componente de seguranca.

Vulnerabilidades Comuns de API e Mitigacoes

O OWASP API Security Top 10 identifica vulnerabilidades recorrentes em APIs. O Symfony fornece protecao integrada para varias delas:

VulnerabilidadeMitigacao Symfony
Broken Object Level AuthorizationVoters com verificacao de propriedade
Broken AuthenticationThrottling de login, hashing seguro
Excessive Data ExposureGrupos de serializacao DTO
Lack of Rate LimitingComponente RateLimiter
Mass AssignmentValidacao de formularios, mapeamento DTO
Security MisconfigurationSecurity checker, variaveis de ambiente

Para protecao contra mass assignment, nunca se deve hidratar entidades diretamente dos dados do request:

src/Dto/CreateArticleDto.phpphp
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,
        
        // Intencionalmente omitido: author, createdAt, status
        // Esses valores sao definidos pela aplicacao, nao pelo cliente
    ) {}
}

A abordagem de whitelist via DTO impede que os clientes definam campos que nao deveriam controlar, como isAdmin ou createdAt.

Configuracao CORS para Consumidores de API

Os headers Cross-Origin Resource Sharing controlam quais dominios podem chamar a API a partir de navegadores. O bundle nelmio/cors-bundle fornece configuracao declarativa:

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

Deve-se evitar allow_origin: ['*'] com allow_credentials: true. Essa combinacao expoe a API ao roubo de credenciais por sites maliciosos. Whitelists de dominios explicitas ou padroes regex sao preferiveis.

Perguntas de Entrevista Tecnica sobre Seguranca de API Symfony

Essas perguntas aparecem frequentemente em entrevistas para desenvolvedores Symfony senior. As respostas refletem as capacidades do Symfony 7.3.

P: Como o Symfony gerencia a validacao de tokens de acesso OAuth2?

O Symfony 7.3 suporta tres abordagens: validacao JWT local com verificacao de assinatura, chamadas ao endpoint user info do OIDC e introspection de token RFC 7662. A introspection e adequada para tokens opacos ou cenarios onde a aplicacao nao controla o servidor de autorizacao. O AccessTokenHandler abstrai as tres abordagens por tras de uma interface unificada.

P: Qual e a diferenca entre firewalls e access control no Symfony?

Os firewalls definem mecanismos de autenticacao por padrao de URL. As regras de access control definem requisitos de autorizacao apos a autenticacao ser bem-sucedida. Um firewall pode exigir um JWT valido, enquanto access control exige ROLE_ADMIN para /api/admin/*. Eles operam em sequencia: o firewall autentica, depois o access control autoriza.

P: Como prevenir ataques de forca bruta em um endpoint de login?

O throttling de login integrado do Symfony limita tentativas falhas por nome de usuario e IP. A configuracao de login_throttling e feita no firewall:

yaml
security:
    firewalls:
        main:
            login_throttling:
                max_attempts: 5
                interval: '15 minutes'

Para autenticacao de API, deve-se combinar com o componente RateLimiter no endpoint de token. Os contadores de tentativas sao armazenados no Redis para implantacoes multi-instancia.

P: Explique os Voters do Symfony e quando usa-los em vez de simples verificacoes de roles.

Os Voters implementam logica de autorizacao complexa que depende do recurso, nao apenas do role do usuario. Deve-se usar Voters quando: o usuario precisa ser proprietario do recurso, o recurso tem uma maquina de estados (rascunho vs publicado), ou a autorizacao depende de regras de negocio (nivel de assinatura). Verificacoes de roles sao suficientes para permissoes estaticas como "apenas admins podem acessar configuracoes".

Para mais perguntas de seguranca Symfony, consulte o guia de preparacao para entrevistas Symfony.

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Construindo uma API Symfony Segura: Pontos-Chave

  • Configurar introspection de tokens OAuth2 para provedores de identidade externos quando o formato do token e opaco
  • Aplicar rate limiting no nivel de infraestrutura (reverse proxy) e no nivel de aplicacao (componente RateLimiter) para defesa em profundidade
  • Usar Voters para autorizacao no nivel de recurso, reservando verificacoes de roles para permissoes estaticas
  • Mapear dados do request para DTOs com propriedades explicitas para prevenir mass assignment
  • Armazenar segredos em variaveis de ambiente, nunca em arquivos config/*.yaml versionados
  • Testar regras de seguranca com testes funcionais WebTestCase que verificam acessos permitidos e negados
  • Auditar dependencias com symfony security:check em pipelines de CI
Desafio do dia

Você saberia encontrar o bug em Symfony?

Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador da SharpSkill

Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.

Atualizado em 14 de setembro de 2026

Compartilhar

Artigos relacionados