2026'da Symfony REST API Güvenliği: OAuth2, Rate Limiting ve Mülakat Soruları

Symfony REST API'lerini OAuth2 token introspection, rate limiting ve JWT doğrulama ile güvence altına alma rehberi. Symfony 7.3 güvenlik özellikleri ve mülakat soruları.

2026'da Symfony REST API Güvenliği: OAuth2, Rate Limiting ve Mülakat Soruları

Symfony REST API güvenliği, kimlik doğrulama, yetkilendirme ve trafik kontrolünü birleştiren katmanlı bir yaklaşım gerektirir. Symfony 7.3, RFC 7662 aracılığıyla yerel OAuth2 token introspection desteği sunarken, RateLimiter bileşeni kötüye kullanıma karşı yerleşik koruma sağlar.

Symfony API'leri için Temel Güvenlik Katmanları

Üretime hazır bir Symfony API üç savunma katmanına ihtiyaç duyar: kimlik doğrulama (kim çağırıyor), yetkilendirme (neye erişebilir) ve rate limiting (ne sıklıkta). Herhangi bir katmanın eksikliği uygulamayı credential stuffing, veri sızıntısı veya hizmet reddi saldırılarına maruz bırakır.

Symfony 7.3'te OAuth2 Token Introspection

Symfony 7.3, OAuth2 Token Introspection (RFC 7662) için yerleşik destek ekler. Bu özellik, tokenları yerel olarak çözümleme ihtiyacını ortadan kaldırarak doğrudan yetkilendirme sunucusunu sorgulayarak erişim tokenlarını doğrular. Token formatı opak olduğunda veya üçüncü taraf bir kimlik sağlayıcısı tarafından kontrol edildiğinde bu önemlidir.

AccessTokenHandler yapılandırması bir introspection endpoint'i kabul eder:

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)%'

Introspection yanıtı active, scope, client_id ve isteğe bağlı olarak username içerir. Symfony bunları otomatik olarak güvenlik özniteliklerine eşler.

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 zaten introspection ile doğrulandı
        $user = $this->getUser();
        
        return $this->json([
            'id' => $user->getId(),
            'email' => $user->getEmail(),
            'scopes' => $user->getRoles(),
        ]);
    }
}

Bu, JWT imza doğrulama yükünü uygulamadan yetkilendirme sunucusuna aktarır. Yetkilendirme sunucusu anahtar rotasyonu, token iptali ve kapsam doğrulamasını üstlenir.

RateLimiter Bileşeni ile Rate Limiting Uygulaması

RateLimiter bileşeni, token bucket veya sliding window algoritmaları kullanarak endpoint'leri kötüye kullanıma karşı korur. Yapılandırma framework.yaml içinde yapılır:

yaml
# config/packages/framework.yaml
framework:
    rate_limiter:
        # Genel API limiti: dakikada 100 istek
        api_limiter:
            policy: sliding_window
            limit: 100
            interval: '1 minute'
            
        # Kimlik doğrulama endpoint'leri için daha sıkı limit
        login_limiter:
            policy: token_bucket
            limit: 5
            rate: { interval: '1 minute', amount: 5 }

Rate limiting, bir event subscriber kullanarak controller'lara uygulanabilir:

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();
        
        // Sadece API rotalarına uygula
        if (!str_starts_with($request->getPathInfo(), '/api')) {
            return;
        }
        
        // Limiter anahtarı olarak istemci IP veya kimliği doğrulanmış kullanıcı kullan
        $key = $request->getClientIp();
        $limiter = $this->apiLimiter->create($key);
        
        if (!$limiter->consume()->isAccepted()) {
            throw new TooManyRequestsHttpException();
        }
    }
}

Kimliği doğrulanmış API'ler için, tek bir kötüye kullanan kullanıcının aynı ağdan gelen meşru trafiği etkilemesini önlemek amacıyla IP tabanlı anahtar yerine kullanıcı tanımlayıcısı kullanılabilir.

Harici Bağımlılık Olmadan JWT Doğrulama

Yetkilendirme sunucusu bilinen bir genel anahtarla JWT'ler verdiğinde, Symfony OidcUserInfoTokenHandler kullanarak tokenları yerel olarak doğrulayabilir:

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

OIDC sağlayıcısı olmayan kendi JWT'leriniz için lexik/jwt-authentication-bundle kullanılabilir:

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
    {
        // Otomatik olarak çözer ve imzayı doğrular
        $payload = $this->jwtManager->parse($accessToken);
        
        return new UserBadge($payload['sub']);
    }
}

JWT bundle, RS256/ES256 imza doğrulaması, süre sonu kontrolü ve yayıncı doğrulamasını üstlenir. Genel anahtar config/jwt/public.pem içinde saklanmalı ve lexik_jwt_authentication.yaml içinde referans verilmelidir.

Symfony mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Voter'lar ile API Endpoint'lerini Güvence Altına Alma

Symfony Voter'lar, basit rol kontrollerinin ötesinde ayrıntılı yetkilendirme sağlar. Yaygın bir desen, kaynak sahipliğini kontrol eder:

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;
        
        // Yöneticiler her şeyi yapabilir
        if (in_array('ROLE_ADMIN', $user->getRoles(), true)) {
            return true;
        }
        
        // Yazarlar kendi makalelerini düzenleyebilir/silebilir
        return $article->getAuthor() === $user;
    }
}

Controller'larda voter kullanımı:

php
#[Route('/api/articles/{id}', methods: ['PUT'])]
public function update(Article $article, Request $request): JsonResponse
{
    $this->denyAccessUnlessGranted(ArticleVoter::EDIT, $article);
    
    // Güncelleme mantığı
}

Voter'lar yetkilendirme mantığını merkezileştirir ve test edilebilir hale getirir. Ayrıca güvenlik bileşeni hakkındaki Symfony mülakat sorularında sıklıkla karşılaşılır.

Yaygın API Güvenlik Açıkları ve Çözümleri

OWASP API Security Top 10, API'lerde tekrarlayan güvenlik açıklarını tanımlar. Symfony birçoğuna karşı yerleşik koruma sağlar:

Güvenlik AçığıSymfony Koruması
Broken Object Level AuthorizationSahiplik kontrollü Voter'lar
Broken AuthenticationGiriş throttling, güvenli şifre hash'leme
Excessive Data ExposureDTO serileştirme grupları
Lack of Rate LimitingRateLimiter bileşeni
Mass AssignmentForm doğrulama, DTO eşleme
Security MisconfigurationSymfony security checker, ortam değişkenleri

Mass assignment koruması için entity'ler asla doğrudan istek verilerinden hydrate edilmemelidir:

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,
        
        // Kasıtlı olarak çıkarıldı: author, createdAt, status
        // Bunlar uygulama tarafından ayarlanır, istemci tarafından değil
    ) {}
}

DTO beyaz liste yaklaşımı, istemcilerin isAdmin veya createdAt gibi kontrol etmemeleri gereken alanları ayarlamasını engeller.

API Tüketicileri için CORS Yapılandırması

Cross-Origin Resource Sharing başlıkları, hangi domain'lerin API'yi tarayıcılardan çağırabileceğini kontrol eder. nelmio/cors-bundle, bildirimsel yapılandırma sağlar:

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

allow_origin: ['*'] ile allow_credentials: true kombinasyonundan kaçınılmalıdır. Bu kombinasyon, API'yi kötü niyetli siteler aracılığıyla kimlik bilgisi hırsızlığına maruz bırakır. Açık domain beyaz listeleri veya regex kalıpları tercih edilmelidir.

Symfony API Güvenliği Teknik Mülakat Soruları

Bu sorular, kıdemli Symfony geliştirici mülakatlarında sıklıkla karşılaşılır. Cevaplar Symfony 7.3 yeteneklerini yansıtır.

S: Symfony OAuth2 erişim token doğrulamasını nasıl yönetir?

Symfony 7.3 üç yaklaşımı destekler: imza doğrulamalı yerel JWT doğrulama, OIDC user info endpoint çağrıları ve RFC 7662 token introspection. Introspection, opak tokenlar veya uygulamanın yetkilendirme sunucusunu kontrol etmediği senaryolar için uygundur. AccessTokenHandler üçünü de birleşik bir arayüz arkasında soyutlar.

S: Symfony'de firewall'lar ve access control arasındaki fark nedir?

Firewall'lar, URL kalıpları için kimlik doğrulama mekanizmalarını tanımlar. Access control kuralları, kimlik doğrulama başarılı olduktan sonra yetkilendirme gereksinimlerini tanımlar. Bir firewall geçerli bir JWT gerektirebilirken, access control /api/admin/* için ROLE_ADMIN gerektirebilir. Sıralı olarak çalışırlar: firewall kimlik doğrular, sonra access control yetkilendirir.

S: Giriş endpoint'ine brute force saldırılarını nasıl önlersiniz?

Symfony'nin yerleşik giriş throttling'i, kullanıcı adı ve IP başına başarısız denemeleri sınırlar. Firewall'da login_throttling yapılandırması:

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

API kimlik doğrulaması için, token endpoint'inde RateLimiter bileşeni ile birleştirilmelidir. Çoklu instance dağıtımları için deneme sayaçları Redis'te saklanmalıdır.

S: Symfony Voter'ları açıklayın ve basit rol kontrollerine göre ne zaman kullanılmalıdır.

Voter'lar, yalnızca kullanıcı rolüne değil, kaynağa bağlı karmaşık yetkilendirme mantığı uygular. Voter'lar şu durumlarda kullanılmalıdır: kullanıcı kaynağın sahibi olmalıdır, kaynak bir durum makinesine sahiptir (taslak vs yayınlanmış) veya yetkilendirme iş kurallarına bağlıdır (abonelik seviyesi). Rol kontrolleri "sadece yöneticiler ayarlara erişebilir" gibi statik izinler için yeterlidir.

Daha fazla Symfony güvenlik sorusu için Symfony mülakat hazırlık rehberine bakılabilir.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Güvenli Symfony API Oluşturma: Temel Çıkarımlar

  • Token formatı opak olduğunda üçüncü taraf kimlik sağlayıcıları için OAuth2 token introspection yapılandırılmalıdır
  • Derinlemesine savunma için hem altyapı düzeyinde (reverse proxy) hem de uygulama düzeyinde (RateLimiter bileşeni) rate limiting uygulanmalıdır
  • Kaynak düzeyinde yetkilendirme için Voter'lar kullanılmalı, rol kontrolleri statik izinler için ayrılmalıdır
  • Mass assignment'ı önlemek için istek verileri açık özelliklere sahip DTO'lara eşlenmelidir
  • Gizli bilgiler ortam değişkenlerinde saklanmalı, asla sürüm kontrolüne commit edilen config/*.yaml dosyalarında bulunmamalıdır
  • Güvenlik kuralları, hem izin verilen hem de reddedilen erişimi doğrulayan WebTestCase fonksiyonel testleri ile test edilmelidir
  • CI pipeline'larında symfony security:check ile bağımlılıklar denetlenmelidir
Günün meydan okuması

Symfony kodundaki hatayı bulabilir misin?

Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

14 Eylül 2026 tarihinde güncellendi

Paylaş

İlgili makaleler