Keamanan REST API Symfony di 2026: OAuth2, Rate Limiting, dan Pertanyaan Interview
Pelajari cara mengamankan REST API Symfony dengan OAuth2 token introspection, rate limiting, dan validasi JWT. Membahas fitur keamanan Symfony 7.3, kerentanan umum, dan pertanyaan interview teknis.

Keamanan REST API Symfony membutuhkan pendekatan berlapis yang menggabungkan autentikasi, otorisasi, dan kontrol lalu lintas. Symfony 7.3 memperkenalkan dukungan native OAuth2 token introspection melalui RFC 7662, sementara komponen RateLimiter menyediakan perlindungan bawaan terhadap penyalahgunaan.
API Symfony yang siap produksi membutuhkan tiga pertahanan: autentikasi (siapa yang memanggil), otorisasi (apa yang dapat diakses), dan rate limiting (seberapa sering). Mengabaikan salah satu lapisan akan mengekspos aplikasi terhadap credential stuffing, eksfiltrasi data, atau denial of service.
OAuth2 Token Introspection di Symfony 7.3
Symfony 7.3 menambahkan dukungan bawaan untuk OAuth2 Token Introspection (RFC 7662). Fitur ini memvalidasi access token dengan melakukan query langsung ke authorization server, menghilangkan kebutuhan untuk mendekode token secara lokal. Ini penting ketika format token bersifat opaque atau dikontrol oleh identity provider pihak ketiga.
Konfigurasi AccessTokenHandler menerima endpoint introspection:
# 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)%'Response introspection berisi active, scope, client_id, dan opsional username. Symfony memetakan ini ke atribut keamanan secara otomatis.
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 sudah divalidasi melalui introspection
$user = $this->getUser();
return $this->json([
'id' => $user->getId(),
'email' => $user->getEmail(),
'scopes' => $user->getRoles(),
]);
}
}Pendekatan ini menghilangkan beban verifikasi signature JWT dari aplikasi. Authorization server menangani rotasi key, pencabutan token, dan validasi scope.
Implementasi Rate Limiting dengan Komponen RateLimiter
Komponen RateLimiter melindungi endpoint dari penyalahgunaan menggunakan algoritma token bucket atau sliding window. Konfigurasi dilakukan di framework.yaml:
# config/packages/framework.yaml
framework:
rate_limiter:
# Rate limit API umum: 100 request per menit
api_limiter:
policy: sliding_window
limit: 100
interval: '1 minute'
# Limit lebih ketat untuk endpoint autentikasi
login_limiter:
policy: token_bucket
limit: 5
rate: { interval: '1 minute', amount: 5 }Terapkan rate limiting ke controller menggunakan event subscriber:
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();
// Hanya terapkan ke route API
if (!str_starts_with($request->getPathInfo(), '/api')) {
return;
}
// Gunakan IP client atau user terautentikasi sebagai limiter key
$key = $request->getClientIp();
$limiter = $this->apiLimiter->create($key);
if (!$limiter->consume()->isAccepted()) {
throw new TooManyRequestsHttpException();
}
}
}Untuk API terautentikasi, ganti key berbasis IP dengan identifier user untuk mencegah satu user yang menyalahgunakan mempengaruhi traffic legitimate dari jaringan yang sama.
Validasi JWT Tanpa Dependensi Eksternal
Ketika authorization server menerbitkan JWT dengan public key yang diketahui, Symfony dapat memvalidasi token secara lokal menggunakan OidcUserInfoTokenHandler:
# config/packages/security.yaml
security:
firewalls:
api:
pattern: ^/api
stateless: true
access_token:
token_handler:
oidc_user_info:
base_uri: '%env(OIDC_ISSUER)%'
claim: emailUntuk JWT yang diterbitkan sendiri tanpa provider OIDC, gunakan lexik/jwt-authentication-bundle:
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
{
// Decode dan validasi signature secara otomatis
$payload = $this->jwtManager->parse($accessToken);
return new UserBadge($payload['sub']);
}
}Bundle JWT menangani verifikasi signature RS256/ES256, pengecekan expiration, dan validasi issuer. Simpan public key di config/jwt/public.pem dan referensikan di lexik_jwt_authentication.yaml.
Siap menguasai wawancara Symfony Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Mengamankan Endpoint API dengan Voters
Symfony Voters menyediakan otorisasi fine-grained di luar pengecekan role sederhana. Pola umum memeriksa kepemilikan resource:
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;
// Admin dapat melakukan apa saja
if (in_array('ROLE_ADMIN', $user->getRoles(), true)) {
return true;
}
// Penulis dapat mengedit/menghapus artikel mereka sendiri
return $article->getAuthor() === $user;
}
}Gunakan voter di controller:
#[Route('/api/articles/{id}', methods: ['PUT'])]
public function update(Article $article, Request $request): JsonResponse
{
$this->denyAccessUnlessGranted(ArticleVoter::EDIT, $article);
// Logika update di sini
}Voters memusatkan logika otorisasi dan membuatnya dapat diuji. Mereka juga sering muncul dalam pertanyaan interview Symfony tentang komponen keamanan.
Kerentanan API Umum dan Mitigasinya
OWASP API Security Top 10 mengidentifikasi kerentanan yang berulang dalam API. Symfony menyediakan perlindungan bawaan untuk beberapa di antaranya:
| Kerentanan | Mitigasi Symfony |
|---|---|
| Broken Object Level Authorization | Voters dengan pengecekan kepemilikan |
| Broken Authentication | Login throttling, secure password hashing |
| Excessive Data Exposure | Grup serialisasi DTO |
| Lack of Rate Limiting | Komponen RateLimiter |
| Mass Assignment | Validasi form, mapping DTO |
| Security Misconfiguration | Security checker Symfony, env vars |
Untuk perlindungan mass assignment, jangan pernah melakukan hydrate entity langsung dari data request:
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,
// Sengaja dihilangkan: author, createdAt, status
// Ini di-set oleh aplikasi, bukan client
) {}
}Pendekatan whitelist DTO mencegah client mengatur field yang tidak seharusnya mereka kontrol, seperti isAdmin atau createdAt.
Konfigurasi CORS untuk Consumer API
Header Cross-Origin Resource Sharing mengontrol domain mana yang dapat memanggil API dari browser. Bundle nelmio/cors-bundle menyediakan konfigurasi deklaratif:
# 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: trueHindari allow_origin: ['*'] dengan allow_credentials: true. Kombinasi ini mengekspos API terhadap pencurian kredensial melalui situs berbahaya. Gunakan whitelist domain eksplisit atau pola regex.
Pertanyaan Interview Teknis tentang Keamanan API Symfony
Pertanyaan-pertanyaan ini sering muncul dalam interview developer Symfony senior. Jawaban mencerminkan kemampuan Symfony 7.3.
T: Bagaimana Symfony menangani validasi access token OAuth2?
Symfony 7.3 mendukung tiga pendekatan: validasi JWT lokal dengan verifikasi signature, panggilan endpoint user info OIDC, dan token introspection RFC 7662. Introspection cocok untuk token opaque atau skenario di mana aplikasi tidak mengontrol authorization server. AccessTokenHandler mengabstraksi ketiganya di balik interface yang seragam.
T: Apa perbedaan antara firewall dan access control di Symfony?
Firewall mendefinisikan mekanisme autentikasi per pola URL. Aturan access control mendefinisikan persyaratan otorisasi setelah autentikasi berhasil. Firewall mungkin membutuhkan JWT yang valid, sementara access control membutuhkan ROLE_ADMIN untuk /api/admin/*. Mereka beroperasi secara berurutan: firewall melakukan autentikasi, kemudian access control melakukan otorisasi.
T: Bagaimana cara mencegah serangan brute force pada endpoint login?
Login throttling bawaan Symfony membatasi percobaan gagal per username dan IP. Konfigurasikan login_throttling di firewall:
security:
firewalls:
main:
login_throttling:
max_attempts: 5
interval: '15 minutes'Untuk autentikasi API, kombinasikan dengan komponen RateLimiter pada endpoint token. Simpan hitungan percobaan di Redis untuk deployment multi-instance.
T: Jelaskan Symfony Voters dan kapan menggunakannya dibanding pengecekan role sederhana.
Voters mengimplementasikan logika otorisasi kompleks yang bergantung pada resource, bukan hanya role user. Gunakan voters ketika: user harus memiliki resource, resource memiliki state machine (draft vs published), atau otorisasi bergantung pada aturan bisnis (tier subscription). Pengecekan role cukup untuk permission statis seperti "hanya admin yang dapat mengakses settings."
Untuk pertanyaan keamanan Symfony lainnya, lihat panduan persiapan interview Symfony.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Membangun API Symfony yang Aman: Poin-Poin Penting
- Konfigurasikan OAuth2 token introspection untuk identity provider pihak ketiga di mana format token bersifat opaque
- Terapkan rate limiting di level infrastruktur (reverse proxy) dan level aplikasi (komponen RateLimiter) untuk defense in depth
- Gunakan Voters untuk otorisasi level resource, cadangkan pengecekan role untuk permission statis
- Petakan data request ke DTO dengan properti eksplisit untuk mencegah mass assignment
- Simpan secret di environment variable, jangan pernah di file
config/*.yamlyang di-commit ke version control - Uji aturan keamanan dengan functional test
WebTestCaseyang memverifikasi akses yang diizinkan dan ditolak - Audit dependency dengan
symfony security:checkdi pipeline CI
Bisakah kamu menemukan bug di Symfony?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 14 September 2026
Tag
Bagikan
Artikel terkait

Keamanan Symfony 2026: Voters, Firewalls, dan Pertanyaan Wawancara Teknis
Panduan lengkap keamanan Symfony: konfigurasi firewall, Access Token Handler stateless, sistem voter untuk otorisasi granular, atribut IsGranted, strategi access decision, debugging Twig di 7.4, serta pertanyaan wawancara teknis yang sering muncul.

Pengujian Symfony di 2026: PHPUnit, KernelTestCase, dan Functional Tests
Panduan lengkap pengujian aplikasi Symfony menggunakan PHPUnit 12, KernelTestCase untuk integration testing, dan WebTestCase untuk functional tests dengan praktik terbaik.

Symfony Live Components dan UX 3.0: Aplikasi Reaktif Tanpa JavaScript di 2026
Symfony Live Components memungkinkan pengembangan antarmuka reaktif dengan PHP dan Twig tanpa JavaScript. Tutorial lengkap LiveProp, LiveAction, form, dan deferred loading.