Symfony REST API Guvenliği: Kimlik Doğrulama, JWT ve 2026 Mulakat Soruları

Symfony REST API guvenliği icin kapsamlı rehber. JWT kimlik doğrulama, guvenlik en iyi uygulamaları ve 2026 mulakat sorularına hazırlık.

Symfony REST API Guvenliği: Kimlik Doğrulama, JWT ve 2026 Mulakat Soruları

REST API guvenliği modern web uygulamalarının temel taşlarından birini oluşturmaktadır. Symfony ekosistemi, geliştiricilere guclü koruma mekanizmalarını uygulamak icin gelişmiş araclar ve bileşenler sunmaktadır. Bu rehber, API guvenliğinin en onemli yonlerini ele almakta ve 2026 yılı mulakat sorularına hazırlık sağlamaktadır.

Symfony Security Component 7.x surumunde JWT token desteği ve firewall yonetimi konusunda onemli iyileştirmeler yapılmıştır. Uygulama oncesinde guncel dokumantasyonu incelemek faydalı olacaktır.

Symfony'de Guvenlik Mimarisi

Symfony Security, uygulamanın farklı koruma katmanlarından sorumlu birkaç temel bileşenden oluşmaktadır. Bu mimariyi anlamak, guvenlik yapılandırmasının doğru şekilde gercekleştirilmesi icin zorunludur.

Security bileşeni iki ana alana ayrılmaktadır: kimlik doğrulama (authentication) ve yetkilendirme (authorization). Kimlik doğrulama kullanıcının kimliğini doğrularken, yetkilendirme erişilebilir kaynakları ve işlemleri belirlemektedir.

yaml
# config/packages/security.yaml
security:
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: "auto"
    
    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        api:
            pattern: ^/api
            stateless: true
            jwt: ~
        main:
            lazy: true
            provider: app_user_provider

JWT Authentication Uygulaması

JSON Web Token (JWT), taraflar arasında guvenli bilgi alışverişini JSON nesnesi olarak sağlayan bir standarttır. REST API bağlamında JWT tokenları, sunucu tarafında oturum saklamaya gerek kalmadan isteklerin kimlik doğrulamasını gercekleştirmektedir.

LexikJWTAuthenticationBundle paketinin kurulumu yapılandırma surecini başlatmaktadır:

bash
composer require lexik/jwt-authentication-bundle

Kriptografik anahtarların oluşturulması icin aşağıdaki komutlar calistırılmalıdır:

bash
php bin/console lexik:jwt:generate-keypair

Paketin yapılandırma dosyasındaki ayarları:

yaml
# config/packages/lexik_jwt_authentication.yaml
lexik_jwt_authentication:
    secret_key: "%env(resolve:JWT_SECRET_KEY)%"
    public_key: "%env(resolve:JWT_PUBLIC_KEY)%"
    pass_phrase: "%env(JWT_PASSPHRASE)%"
    token_ttl: 3600
    token_extractors:
        authorization_header:
            enabled: true
            prefix: Bearer
            name: Authorization

Giriş Endpoint'i ve Token Uretimi

Kullanıcı kimlik doğrulaması ve JWT token uretiminden sorumlu controller:

php
<?php

namespace App\Controller\Api;

use App\Repository\UserRepository;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;

#[Route("/api")]
class AuthController extends AbstractController
{
    public function __construct(
        private UserRepository $userRepository,
        private UserPasswordHasherInterface $passwordHasher,
        private JWTTokenManagerInterface $jwtManager,
    ) {}

    #[Route("/login", name: "api_login", methods: ["POST"])]
    public function login(Request $request): JsonResponse
    {
        $data = json_decode($request->getContent(), true);
        
        $user = $this->userRepository->findOneBy(["email" => $data["email"] ?? ""]);
        
        if (!$user || !$this->passwordHasher->isPasswordValid($user, $data["password"] ?? "")) {
            return new JsonResponse(["error" => "Invalid credentials"], 401);
        }
        
        $token = $this->jwtManager->create($user);
        
        return new JsonResponse([
            "token" => $token,
            "expires_in" => 3600,
        ]);
    }
}

Token Doğrulama ve Yenileme

Token yenileme mekanizması, yeniden giriş gerektirmeden oturum surekliliğini sağlamaktadır:

php
<?php

namespace App\Service;

use App\Entity\RefreshToken;
use App\Repository\RefreshTokenRepository;
use Doctrine\ORM\EntityManagerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class TokenRefreshService
{
    public function __construct(
        private RefreshTokenRepository $refreshTokenRepository,
        private EntityManagerInterface $entityManager,
        private JWTTokenManagerInterface $jwtManager,
    ) {}

    public function createRefreshToken(UserInterface $user): string
    {
        $token = bin2hex(random_bytes(64));
        
        $refreshToken = new RefreshToken();
        $refreshToken->setToken(hash("sha256", $token));
        $refreshToken->setUser($user);
        $refreshToken->setExpiresAt(new \DateTimeImmutable("+30 days"));
        
        $this->entityManager->persist($refreshToken);
        $this->entityManager->flush();
        
        return $token;
    }

    public function refresh(string $token): ?array
    {
        $hashedToken = hash("sha256", $token);
        $refreshToken = $this->refreshTokenRepository->findOneBy(["token" => $hashedToken]);
        
        if (!$refreshToken || $refreshToken->isExpired()) {
            return null;
        }
        
        $user = $refreshToken->getUser();
        $jwt = $this->jwtManager->create($user);
        
        return [
            "token" => $jwt,
            "refresh_token" => $this->rotateRefreshToken($refreshToken, $user),
        ];
    }

    private function rotateRefreshToken(RefreshToken $oldToken, UserInterface $user): string
    {
        $this->entityManager->remove($oldToken);
        return $this->createRefreshToken($user);
    }
}

Erişim Kontrolu ve Voter'lar

Symfony'deki Voter sistemi karmaşık yetkilendirme mantığının uygulanmasını mumkun kılmaktadır:

php
<?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;

class ArticleVoter extends Voter
{
    public const EDIT = "ARTICLE_EDIT";
    public const DELETE = "ARTICLE_DELETE";
    public const VIEW = "ARTICLE_VIEW";

    protected function supports(string $attribute, mixed $subject): bool
    {
        return in_array($attribute, [self::EDIT, self::DELETE, self::VIEW])
            && $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;

        return match($attribute) {
            self::VIEW => $this->canView($article, $user),
            self::EDIT => $this->canEdit($article, $user),
            self::DELETE => $this->canDelete($article, $user),
            default => false,
        };
    }

    private function canView(Article $article, User $user): bool
    {
        return $article->isPublished() || $article->getAuthor() === $user;
    }

    private function canEdit(Article $article, User $user): bool
    {
        return $article->getAuthor() === $user || in_array("ROLE_EDITOR", $user->getRoles());
    }

    private function canDelete(Article $article, User $user): bool
    {
        return in_array("ROLE_ADMIN", $user->getRoles());
    }
}

Rate Limiting ve Saldırı Koruması

İstek sınırlandırma, API'yi brute-force saldırılarına karşı korumaktadır:

php
<?php

namespace App\EventListener;

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\RateLimiter\RateLimiterFactory;

#[AsEventListener(event: "kernel.request", priority: 100)]
class RateLimitListener
{
    public function __construct(
        private RateLimiterFactory $apiLimiter,
    ) {}

    public function __invoke(RequestEvent $event): void
    {
        $request = $event->getRequest();
        
        if (!str_starts_with($request->getPathInfo(), "/api")) {
            return;
        }
        
        $limiter = $this->apiLimiter->create($request->getClientIp());
        $limit = $limiter->consume();
        
        if (!$limit->isAccepted()) {
            $response = new JsonResponse(
                ["error" => "Too many requests", "retry_after" => $limit->getRetryAfter()->getTimestamp()],
                429
            );
            $response->headers->set("Retry-After", $limit->getRetryAfter()->getTimestamp());
            $event->setResponse($response);
        }
    }
}

Girdi Doğrulama

Girdi verilerinin doğru şekilde doğrulanması ilk savunma hattını oluşturmaktadır:

php
<?php

namespace App\Dto;

use Symfony\Component\Validator\Constraints as Assert;

class CreateUserRequest
{
    #[Assert\NotBlank]
    #[Assert\Email]
    public string $email;

    #[Assert\NotBlank]
    #[Assert\Length(min: 8, max: 128)]
    #[Assert\PasswordStrength(minScore: 3)]
    public string $password;

    #[Assert\NotBlank]
    #[Assert\Length(min: 2, max: 100)]
    public string $name;
}

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

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

Mulakat Soruları - API Guvenliği

2026 yılında teknik mulakatlarda adayların aşağıdaki sorularla karşılaşması beklenmektedir:

Kimlik doğrulama ile yetkilendirme arasındaki fark nedir? Kimlik doğrulama kullanıcının kimliğini doğrulayarak "kim olduğunu" belirlemektedir. Yetkilendirme ise izinleri belirleyerek "ne yapabileceğini" ortaya koymaktadır.

JWT tokenlarının oturumlara gore avantajları nelerdir? JWT tokenları durumsuz (stateless) yapıdadır, bu da uygulamanın kolayca olceklenmesini sağlamaktadır. Sunucu tarafında oturum verisi saklamayı gerektirmez ve mikroservis mimarisinde mukemmel şekilde calışmaktadır.

API'yi CSRF saldırılarına karşı nasıl korunur? Authorization başlığında JWT tokenları kullanan REST API'leri CSRF saldırılarına doğal olarak dayanıklıdır, cunku tarayıcılar cross-origin isteklere otomatik olarak başlık eklememektedir.

Refresh token nedir ve neden gereklidir? Refresh token, yeniden giriş yapmadan yeni bir access token almayı mumkun kılmaktadır. Bu sayede kullanıcı rahatlığı korunurken kısa omurlu access tokenları kullanılabilmektedir.

Symfony'de rol hiyerarşisi nasıl uygulanır? Symfony, security.yaml yapılandırması aracılığıyla rol hiyerarşisini desteklemektedir. Ust rol otomatik olarak alt rollerin tum yetkilerini icermektedir.

yaml
security:
    role_hierarchy:
        ROLE_ADMIN: [ROLE_EDITOR, ROLE_USER]
        ROLE_EDITOR: [ROLE_USER]

Hata Yonetimi ve Gunlukleme

Guvenlikle ilgili istisnaların doğru şekilde ele alınması:

php
<?php

namespace App\EventListener;

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Psr\Log\LoggerInterface;

#[AsEventListener(event: "kernel.exception")]
class SecurityExceptionListener
{
    public function __construct(
        private LoggerInterface $securityLogger,
    ) {}

    public function __invoke(ExceptionEvent $event): void
    {
        $exception = $event->getThrowable();
        $request = $event->getRequest();
        
        if ($exception instanceof AuthenticationException) {
            $this->securityLogger->warning("Authentication failed", [
                "ip" => $request->getClientIp(),
                "path" => $request->getPathInfo(),
            ]);
            
            $event->setResponse(new JsonResponse(
                ["error" => "Authentication required"],
                401
            ));
            return;
        }
        
        if ($exception instanceof AccessDeniedException) {
            $this->securityLogger->warning("Access denied", [
                "ip" => $request->getClientIp(),
                "path" => $request->getPathInfo(),
            ]);
            
            $event->setResponse(new JsonResponse(
                ["error" => "Access denied"],
                403
            ));
        }
    }
}

Sonuc

Symfony'de REST API guvenliği, JWT kimlik doğrulama, Voter tabanlı yetkilendirme, girdi doğrulama ve yaygın saldırılara karşı korumayı kapsayan cok katmanlı bir yaklaşım gerektirmektedir. Bu mekanizmaları anlamak ve uygulayabilmek, 2026 yılında teknik mulakatlara hazırlanan her Symfony geliştiricisi icin kritik bir yetkinlik oluşturmaktadır. Security Component guncellemelerini ve guvenlik en iyi uygulamalarını duzenli olarak takip etmek, dayanıklı ve guvenli uygulamalar oluşturmayı mumkun kılmaktadır.

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.

26 Ağustos 2026 tarihinde güncellendi

Paylaş

İlgili makaleler