OWASP Top 10 untuk Backend Engineer

16 min readAdvanced
SecurityOWASPBackendOWASP Top 10

OWASP (Open Worldwide Application Security Project) menerbitkan OWASP Top 10, sebuah daftar sepuluh risiko keamanan aplikasi web paling kritis yang disusun dari data serangan dunia nyata. Daftar ini diperbarui secara berkala; versi terbaru adalah OWASP Top 10 2021. Sebagai backend engineer, Anda adalah garis pertahanan terakhir: semua data, logika bisnis, dan API yang Anda tulis adalah yang paling sering dihadapi penyerang. Artikel ini membahas setiap risiko dengan bahasa sederhana, lengkap dengan contoh serangan, contoh kode Java Spring yang aman, dan cara pencegahannya.

Apa itu OWASP Top 10

OWASP Top 10 bukanlah daftar lengkap semua ancaman yang ada — itu adalah titik awal. Daftar ini disusun dari data statistik nyata (bukan teori), lalu diranking berdasarkan dua hal: prevalensi (seberapa sering terjadi) dan dampak (seberapa parah akibatnya). Jika sebuah kerentanan masuk daftar ini, kemungkinan besar banyak aplikasi di dunia mengalaminya.

Peringkat 2021NamaKategori
A01Broken Access ControlKontrol akses
A02Cryptographic FailuresKriptografi
A03InjectionKualitas & keamanan data
A04Insecure DesignKualitas desain
A05Security MisconfigurationKonfigurasi
A06Vulnerable and Outdated ComponentsKomponen
A07Identification and Authentication FailuresIdentifikasi & autentikasi
A08Software and Data Integrity FailuresIntegritas
A09Security Logging and Monitoring FailuresLogging & monitoring
A10Server-Side Request Forgery (SSRF)Serangan sisi server

Daftar ini berubah antar versi. A10 SSRF bahkan baru masuk di versi 2021 setelah peneliti menemukan lonjakan serangan terhadap layanan cloud. Karena itu, anggap OWASP Top 10 sebagai "radar" yang harus dicek rutin, bukan patokan mati.

Cara membaca artikel ini

Untuk setiap risiko, kita bahas tiga hal secara konsisten:

  1. Apa yang terjadi — deskripsi singkat kerentanannya.
  2. Contoh serangan — skenario nyata yang biasa dieksploitasi.
  3. Cara mencegah — prinsip + contoh kode Java Spring yang aman.

Banyak risiko saling terkait: A07 (autentikasi lemah) bisa memicu A01 (akses tak diotorisasi). Karena itu, anggaplah setiap bagian sebagai layer dari pertahanan yang sama, bukan checklist yang berdiri sendiri.

1. A01 — Broken Access Control

Broken access control (kontrol akses rusak) terjadi ketika aplikasi gagal memastikan pengguna hanya bisa mengakses sumber daya yang memang miliknya. Autentikasi menjawab "siapa Anda?", sedangkan otorisasi menjawab "apakah Anda boleh melakukan ini?". A01 adalah kegagalan di jawaban yang kedua, dan ini kategori paling umum di OWASP Top 10 2021.

Contoh serangan: IDOR

IDOR (Insecure Direct Object Reference) adalah kasus paling klasik. Aplikasi menerima id dari URL lalu mengambil data tanpa memeriksa kepemilikan:

GET /api/orders/123        → milik Anda, ditampilkan (200 OK)
GET /api/orders/124        → milik orang lain, TETAP ditampilkan (200 OK!) ✗

Penyerang cukup mengganti angka id di URL untuk membaca pesanan orang lain. Masalahnya bukan pada GET-nya, tapi pada server yang mempercayai id dari klien tanpa verifikasi kepemilikan.

Pencegahan

Prinsip dasarnya: deny by default — setiap akses ditolak kecuali secara eksplisit diizinkan. Cek kepemilikan dilakukan di service layer, bukan hanya di controller:

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    public Order getOrderForUser(Long orderId, User currentUser) {
        Order order = orderRepository.findById(orderId)
                .orElseThrow(() -> new NotFoundException("Order tidak ditemukan"));

        // Cek kepemilikan: kalau bukan pemiliknya, balas 404 (bukan 403)
        // supaya penyerang tidak bisa "menebak" bahwa data itu ada.
        if (!order.getCustomer().getEmail().equals(currentUser.getEmail())) {
            throw new NotFoundException("Order tidak ditemukan");
        }

        return order;
    }
}

Beberapa aturan praktis:

  • Jangan percaya id dari klien — selalu validasi izin terhadap resource yang diakses.
  • Balas 404 (seolah tidak ada) untuk resource milik orang lain, bukan 403, agar tidak membocorkan keberadaan data.
  • Gunakan Spring Security authorization dengan @PreAuthorize untuk kontrol berbasis peran, dan cek objek-level di service.
  • Batasi method HTTP: jangan izinkan DELETE /api/orders/{id} untuk semua orang.

Ingat: broken access control adalah tentang otorisasi, bukan autentikasi. Login sukses tidak otomatis berarti Anda boleh mengakses apa pun.

2. A02 — Cryptographic Failures

Dulu kategori ini bernama "Sensitive Data Exposure". Nama baru ini lebih akurat karena masalahnya biasanya bukan sekadar "data bocor", melainkan data sensitif tidak dilindungi dengan kriptografi yang benar — saat transit maupun saat istirahat. Contoh: kredensial dikirim lewat HTTP biasa, password disimpan sebagai teks polos, atau nomor kartu kredit disimpan tanpa enkripsi.

Contoh serangan

Data sensitif yang dikirim tanpa HTTPS bisa diintip oleh siapa pun di jalur jaringan (serangan man-in-the-middle). Sementara itu, password yang disimpan sebagai teks polos di database akan langsung terbaca jika database pernah bocor — dan database selalu bisa bocor.

Pencegahan

AreaApa yang harus dilakukan
Saat transitWajib HTTPS/TLS di semua komunikasi; tolak request HTTP di production
Saat istirahatEnkripsi data istirahat (misal kartu kredit, data medis) di database
KredensialJangan simpan rahasia, API key, atau token di kode, file config, atau repo
PasswordHash dengan algoritma yang tepat — lihat password hashing dengan BCrypt
KriptografiJangan pernah membuat algoritma kripto sendiri — selalu gunakan implementasi yang sudah teruji

Sebagai contoh, memaksa HTTPS di Spring Boot cukup dengan konfigurasi Spring Security:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .requiresChannel(channel -> channel.anyRequest().requiresSecure())
        .authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
    return http.build();
}

Aturan emas kriptografi: algoritma kripto yang "dibuat sendiri" hampir pasti lemah. Gunakan standar yang sudah diuji komunitas (BCrypt, AES, TLS), dan serahkan detailnya ke library.

3. A03 — Injection

Injection terjadi ketika input dari pengguna dieksekusi sebagai kode atau perintah oleh aplikasi. Bentuknya beragam: SQL injection, NoSQL injection, LDAP injection, hingga OS command injection. Yang paling sering dan paling merusak adalah SQL injection (OWASP A03 Injection).

Contoh serangan SQL injection

Bayangkan login yang menyusun query dengan concatenation string:

// JANGAN PERNAH lakukan ini!
String sql = "SELECT * FROM users WHERE email = '" + email
        + "' AND password = '" + password + "'";

Jika penyerang memasukkan email ' OR '1'='1, query menjadi:

SELECT * FROM users WHERE email = '' OR '1'='1' AND password = 'x'

Ekspresi '1'='1' selalu bernilai benar, sehingga query mengembalikan seluruh baris users — dan penyerang berhasil "login" sebagai baris pertama, biasanya admin.

Pencegahan: parameterized query

Solusi utamanya adalah jangan pernah menyusun query dengan string concatenation. Gunakan parameterized query, PreparedStatement, atau ORM seperti JPA/Hibernate yang otomatis melakukan parameter binding:

// Aman: nilai diikat sebagai parameter, bukan bagian dari SQL
@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u WHERE u.email = :email")
    Optional<User> findByEmail(@Param("email") String email);
}

JPA/Hibernate (dengan parameter binding) memisahkan struktur SQL dari data, sehingga karakter ' milik penyerang diperlakukan sebagai data biasa, bukan sintaks SQL. Baca lebih dalam di Query, Pagination & SQL Injection.

Prinsip umum untuk semua jenis injection: perlakukan input sebagai data, bukan kode. Jangan menggabungkan string dari pengguna ke SQL, LDAP, shell, maupun query NoSQL. Validasi tipe dan format input juga membantu, tapi parameterization adalah garis pertahanan utamanya.

4. A04 — Insecure Design

Insecure design berbeda dari kerentanan kode: ini adalah kesalahan di tingkat desain atau arsitektur, sebelum sebaris kode pun ditulis. Aplikasi bisa saja diimplementasikan "dengan benar" tapi tetap berbahaya karena desainnya salah. Referensi resmi: OWASP A04 Insecure Design.

Contohnya:

  • Endpoint login tanpa rate limit sehingga mudah di-brute-force.
  • Trust boundary yang salah — misalnya memutuskan bahwa nilai role yang dikirim klien bisa dipercaya.
  • Proses reset password yang bisa dipakai untuk membajak akun orang lain.

Contoh desain yang salah

Sebuah API mengizinkan siapa pun memanggil endpoint admin berulang-ulang tanpa batasan. Secara implementasi tidak ada bug, tetapi desainnya memungkinkan penyalahgunaan (abuse).

Pencegahan

Threat modeling adalah praktik utama: sebelum menulis kode, tanyakan "bagaimana sistem ini bisa disalahgunakan?" dan tulis asumsi keamanan secara eksplisit. Beberapa kontrol desain yang umum:

  • Rate limiting pada endpoint sensitif (login, OTP, search) — lihat CORS, Rate Limit & reCAPTCHA.
  • Validasi di sisi server selalu, jangan pernah mempercayai validasi frontend.
  • Modelkan trust boundary: data apa yang bisa disentuh pengguna, siapa yang boleh menyentuh apa.
  • Gunakan allowlist untuk opsi yang diizinkan, bukan denylist.
// Contoh: batasi jumlah percobaan login per akun
@Component
public class LoginAttemptLimiter {

    private final Map<String, Integer> attempts = new ConcurrentHashMap<>();

    public boolean isLocked(String email) {
        return attempts.getOrDefault(email, 0) >= 5;
    }

    public void onFailedAttempt(String email) {
        attempts.merge(email, 1, Integer::sum);
    }

    public void onSuccess(String email) {
        attempts.remove(email);
    }
}

5. A05 — Security Misconfiguration

Ini adalah kategori "kesalahan pengaturan" (OWASP A05). Kode Anda bisa sempurna, tetapi aplikasi tetap rentan karena konfigurasi yang buruk. Ini kategori yang paling sering dijumpai dalam penetration test, dan penyebabnya biasanya sederhana.

Contoh miskonfigurasi umum

MasalahDampak
Default credentials (misal admin/admin) yang tidak digantiSiapa pun bisa masuk sebagai admin
Stack trace / pesan error lengkap ditampilkan ke penggunaMembocorkan struktur kode & internal aplikasi
Directory listing aktifPenyerang bisa melihat semua file di folder
CORS terlalu longgar (Access-Control-Allow-Origin: * untuk endpoint berautentikasi)Halaman jahat bisa membaca respons API Anda
Halaman debug / admin framework tetap aktifEksploitasi yang sudah dikenal

Pencegahan

Hapus mode debug di production dan pastikan konfigurasi berbeda per environment — gunakan configuration profiles dengan @Profile:

@Configuration
@Profile("dev")
public class DevSecurityConfig {
    // hanya aktif saat profile "dev", misal H2 console atau logging verbose
}

@Configuration
@Profile("prod")
public class ProdSecurityConfig {
    // konfigurasi ketat untuk production
}

Pasang security headers di semua respons, seperti yang direkomendasikan OWASP Secure Headers dan Cheat Sheet Series:

HeaderNilai contohMelindungi dari
X-Frame-OptionsDENYClickjacking (halaman dimuat dalam iframe)
Content-Security-Policydefault-src 'self'XSS dan injeksi konten
X-Content-Type-OptionsnosniffMIME sniffing
Strict-Transport-Securitymax-age=31536000; includeSubDomainsMenurunkan ke HTTP (HSTS)
Referrer-Policyno-referrerKebocoran URL lewat header Referer
Permissions-Policygeolocation=()Penggunaan fitur browser oleh pihak ketiga

Di Spring Security, headers dasar aktif secara default, tapi pastikan nilai CSP Anda tidak kosong:

http.headers(headers -> headers
        .xFrameOptions(options -> options.deny())
        .contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'")));

6. A06 — Vulnerable and Outdated Components

Vulnerable and outdated components artinya aplikasi Anda memakai library, framework, atau dependency yang sudah usang dan diketahui punya celah keamanan (OWASP A06). Setiap dependency adalah kode orang lain yang ikut Anda "deploy" — dan setiap CVE (Common Vulnerabilities and Exposures) yang tidak di-patch adalah pintu yang dibiarkan terbuka.

Contoh

Aplikasi memakai versi lama framework yang ternyata memiliki CVE publik dengan proof-of-concept yang mudah dipakai. Penyerang tidak perlu mencari bug sendiri — cukup memakai exploit yang sudah jadi.

Pencegahan

PraktikCara kerja
Update rutinIkuti release patch; jangan menunda update keamanan
Dependency scannerJalankan OWASP Dependency-Check atau OWASP Dependency-Track di CI/CD
Pantau CVESubscribe ke feed CVE untuk stack yang Anda pakai
Kurangi permukaanHapus dependency yang tidak terpakai

Contoh command di terminal (Maven project):

# Periksa dependency terhadap basis data CVE
./mvnw org.owasp:dependency-check-maven:check

Mental model: setiap dependency menambah "luas permukaan serangan". Jangan menambah library hanya karena nyaman — dan jika sudah menambah, Anda bertanggung jawab untuk terus memperbaruinya.

7. A07 — Identification and Authentication Failures

Identification and Authentication Failures terjadi ketika proses verifikasi identitas bisa dikalahkan: password lemah, login bisa di-brute-force, sesi tidak pernah berakhir, atau mekanisme recovery akun bisa disalahgunakan (OWASP A07).

Contoh serangan

  • Brute force — menebak password berulang-ulang karena tidak ada batasan percobaan.
  • Credential stuffing — mencoba kombinasi email:password yang bocor dari situs lain (karena orang memakai password yang sama di mana-mana).
  • Sesi tak dibatasi — token/sesi yang tidak pernah kedaluwarsa, bahkan setelah logout.

Pencegahan

  • Rate limiting pada endpoint login — lihat CORS, Rate Limit & reCAPTCHA.
  • MFA (multi-factor authentication) untuk akun penting.
  • Lockout sementara setelah beberapa kali gagal — seperti LoginAttemptLimiter di bagian A04.
  • Session timeout — sesi kedaluwarsa otomatis, terutama untuk aktivitas sensitif.
  • Jangan memudahkan email enumeration berlebihan — misalnya perbedaan pesan "email tidak terdaftar" vs "password salah" memberi tahu penyerang bahwa email itu valid. Ini keputusan kebijakan (usability vs security) yang harus disepakati tim.
  • Hash password dengan BCrypt — lihat password hashing dengan BCrypt.
// Maksimal satu sesi per akun; sesi kedaluwarsa otomatis
http.sessionManagement(session -> session
        .maximumSessions(1)
        .expiredUrl("/login?expired"));

// Batasi percobaan login di controller
@PostMapping("/api/auth/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
    if (limiter.isLocked(request.getEmail())) {
        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).build();
    }
    try {
        authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword()));
        limiter.onSuccess(request.getEmail());
        return ResponseEntity.ok().build();
    } catch (BadCredentialsException ex) {
        limiter.onFailedAttempt(request.getEmail());
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }
}

8. A08 — Software and Data Integrity Failures

Software and Data Integrity Failures terjadi ketika kode atau data datang dari sumber yang tidak bisa diverifikasi — supply chain (OWASP A08). Contoh paling sering:

  • Plugin atau library yang dimuat tanpa verifikasi identitas.
  • Deserialization objek dari input yang tidak dipercaya — penyerang mengirim byte serial yang, saat di-deserialize, mengeksekusi kode jahat.
  • CI/CD yang mengambil dependency dari repository tanpa validasi checksum.

Pencegahan

PraktikCara kerja
Pin versionKunci versi dependency yang eksplisit (bukan SNAPSHOT / rentang longgar)
Verifikasi checksumBandingkan checksum artefak dengan nilai resmi dari publisher
Minimalisasi deserializationJangan pernah deserialize objek dari input yang tidak dipercaya
Review supply chainPeriksa package-lock.json, pom.xml, build.gradle secara rutin

Contoh buruk — deserialize dari input pengguna:

// SANGAT BERBAHAYA: jangan deserialize data dari input tak dipercaya
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(request.getFile()));
MyObject obj = (MyObject) ois.readObject();

Aturan praktis: jangan pernah memanggil readObject() / readUnshared() / XMLDecoder pada data yang berasal dari klien atau jaringan. Kalau harus, gunakan format teks aman seperti JSON dengan schema validation, atau allowlist class yang diizinkan.

9. A09 — Security Logging and Monitoring Failures

Tanpa log dan monitoring yang baik, serangan bisa terjadi tanpa disadari (OWASP A09). Banyak insiden besar baru terdeteksi berbulan-bulan setelah terjadi, padahal tanda-tandanya sudah muncul di log. Masalah di kategori ini:

  • Gagal login atau akses aneh tidak pernah dicatat.
  • Log tersimpan tanpa retention yang jelas, atau justru tidak ada monitoring/alert.
  • Log justru mencatat rahasia (password, token) sehingga log yang bocor menjadi kerentanan baru.

Pencegahan

  • Log aksi keamanan: login sukses/gagal, reset password, perubahan role, akses ke data sensitif.
  • Monitoring + alerting: kirim alert ketika ada pola mencurigakan (misal 10 gagal login dalam 1 menit).
  • Jangan log rahasia — redaksi (mask) token, password, dan data pribadi.
// Contoh: log percobaan login gagal dengan konteks yang cukup
@Slf4j
@Component
public class LoginAuditLogger {

    public void logFailedLogin(String email, String ip, String reason) {
        // catat email, ip, dan alasan; JANGAN pernah catat password/token
        log.warn("LOGIN_FAILED email={} ip={} reason={}", email, ip, reason);
    }
}

Implementasi lengkapnya — log terstruktur, alerting, dan observability — sudah dibahas di Observability, Logging & Monitoring.

10. A10 — Server-Side Request Forgery (SSRF)

SSRF (Server-Side Request Forgery) terjadi ketika server diminta membuat request ke URL yang bisa dikendalikan penyerang (OWASP A10). Karena request itu datang dari server, ia dipercaya oleh jaringan internal — persis seperti orang yang memakai kartu identitas karyawan.

Contoh serangan

Fitur "fetch gambar dari URL" atau "preview link" biasanya menerima URL dari pengguna. Jika server memanggil URL itu tanpa validasi, penyerang bisa menyuruh server mengakses:

POST /api/preview
{ "url": "http://169.254.169.254/latest/meta-data/" }

169.254.169.254 adalah link-local address untuk metadata cloud (misal AWS, GCP). Dengan SSRF, penyerang bisa mengambil credential/token instance dari alamat ini, lalu menggunakannya untuk masuk lebih dalam. Contoh kode berbahaya:

// BERBAHAYA: server memanggil URL apa pun dari klien
String url = request.getBody().get("url");
URL target = new URL(url);
HttpURLConnection conn = (HttpURLConnection) target.openConnection();
// ... server meminta URL internal atas nama Anda

Pencegahan

StrategiCara kerja
Whitelist domainHanya izinkan koneksi ke domain yang sudah dikenal
Blok IP internal/privateTolak alamat seperti 127.0.0.1, 10.x, 192.168.x, 169.254.169.254, dan resolve DNS-nya juga
Validasi input URLWajibkan https://, tolak scheme lain (file://, gopher://)
Jangan forward redirectSetelah koneksi, jangan otomatis mengikuti 3xx ke host lain
Segmentasi jaringanPisahkan server web dari layanan internal
// Contoh: validasi URL sebelum membuat request
private static final Set<String> ALLOWED_HOSTS = Set.of("images.example.com");

public boolean isAllowed(URL url) {
    if (!"https".equalsIgnoreCase(url.getProtocol())) {
        return false;
    }
    if (!ALLOWED_HOSTS.contains(url.getHost().toLowerCase())) {
        return false;
    }
    return true; // tambahkan juga resolusi DNS dan larangan IP internal
}

Tabel Ringkasan

#NamaPrinsip pencegahan (satu kalimat)
A01Broken Access ControlSelalu cek otorisasi per resource; deny by default, jangan percaya id dari klien.
A02Cryptographic FailuresLindungi data sensitif dengan HTTPS/TLS, enkripsi istirahat, dan hashing yang benar.
A03InjectionPerlakukan input sebagai data, bukan kode — pakai parameterized query.
A04Insecure DesignPikirkan penyalahgunaan sejak desain: rate limit, trust boundary, validasi server.
A05Security MisconfigurationHardening konfigurasi: hapus debug, pasang security headers, pisahkan environment.
A06Vulnerable and Outdated ComponentsUpdate dependency rutin dan pantau CVE dengan scanner otomatis.
A07Identification and Authentication FailuresBatasi percobaan login, aktifkan MFA, dan batasi umur sesi.
A08Software and Data Integrity FailuresVerifikasi sumber kode/data; jangan deserialize input tak dipercaya.
A09Security Logging and Monitoring FailuresLog aksi keamanan, pantau dan alert, jangan pernah log rahasia.
A10SSRFBatasi ke host yang diizinkan dan blokir akses ke IP internal.

Cara memakai daftar ini

Jangan berhenti di membaca. Praktikkan dengan cara berikut:

  1. Threat modeling singkat — sebelum fitur baru, tulis: data apa yang dilindungi, siapa yang boleh menyentuhnya, dan bagaimana sistem bisa disalahgunakan.
  2. Checklist sebelum rilis — jalankan daftar A01–A10 sebagai review checklist di pull request atau sebelum deploy.
  3. Prioritaskan berdasarkan data — fokuskan pengujian ke data paling sensitif (kredensial, pembayaran, data pribadi). Tidak semua risiko sama beratnya untuk semua aplikasi.
  4. Padukan dengan tooling — dependency scanner, static analysis, dan penetration test berkala melengkapi checklist manual ini.

Kesimpulan

Keamanan bukan fitur tambahan yang dipasang di akhir — ia bagian dari desain aplikasi Anda sejak baris pertama. Tidak ada satu kontrol yang cukup: password hashing melindungi A07, parameterized query melindungi A03, cek kepemilikan melindungi A01, dan seterusnya. Inilah yang disebut defense in depth — banyak lapisan sehingga jika satu lapisan gagal, lapisan berikutnya masih melindungi Anda. OWASP Top 10 adalah peta, bukan tujuan; setiap rilis berikutnya, cek lagi apakah Anda masih aman.

Ringkasan

OWASP Top 10 2021 adalah daftar sepuluh risiko web paling kritis yang disusun dari data nyata: dari A01 broken access control (ganti id di URL bisa melihat data orang lain) sampai A10 SSRF (server disuruh memanggil URL internal). Untuk setiap risiko, kuncinya satu prinsip: jangan percaya input dari klien, validasi dan otorisasi di server, lindungi data dengan kriptografi yang benar, jaga konfigurasi tetap hardened, update dependency, dan catat semua aksi keamanan. Keamanan adalah proses berkelanjutan — bukan sekali selesai.

Lanjut membaca

← Back to technical articles