Sepuluh chapter terakhir membedah kerentanan satu per satu — undefined behavior, out-of-bounds access, use-after-free, buffer overflow, luapan bilangan, format string, validasi input, memori, dan berkas. Industri menyimpan semua pola itu dalam kamus bernama CWE (Common Weakness Enumeration): daftar kelemahan perangkat lunak yang diberi nomor dan deskripsi baku, dirawat oleh MITRE. Chapter ini menjelaskan cara membaca entri CWE, memetakan lima yang paling sering muncul di C++ beserta mitigasinya, lalu menjalankan semuanya dalam satu program mitigasi yang teruji.

CWE: Kamus Kerentanan Bersama #

Setiap kelemahan diberi ID — CWE-787, CWE-416, dan seterusnya — lengkap dengan nama, deskripsi, dan hubungannya dengan kelemahan lain. CWE bukan kumpulan serangan nyata (itu wilayah CVE, untuk lubang spesifik pada produk spesifik), melainkan taksonomi pola: “menulis di luar batas”, “mengakses memori setelah dilepas”. Hubungannya tersusun sebagai pohon. Leluhur CWE-119 (pembatasan operasi dalam batas buffer yang tidak benar) menurunkan, antara lain, CWE-120 (buffer overflow klasik), CWE-787 (tulis di luar batas), dan CWE-125 (baca di luar batas) — pohon yang sama persis dengan perjalanan kita dari chapter buffer-overflow.

Nama yang baku mengubah cara tim bekerja. Laporan pindaian, tiket bug, dan hasil audit bisa saling merujuk tanpa salah paham; tren bisa diukur (“separuh temuan bulan ini CWE-476”); dan mitigasi bisa diaudit ulang di rilis berikutnya. Tanpa kamus bersama, “crash saat input aneh” mudah ditutup dan mudah kembali.

Cara Membaca Sebuah Entri CWE #

Entri di cwe.mitre.org punya struktur yang tetap, dan membacanya dengan urutan yang benar menghemat waktu. Setelah judul dan deskripsi, bagian Common Consequences menjelaskan dampak yang mungkin muncul; Detection Methods mencantumkan alat yang bisa menemukannya; Mitigations dikelompokkan per fase — Implementation untuk aksi langsung di kode, Architecture untuk keputusan desain yang lebih besar; Observed Examples merujuk CVE nyata yang memakai pola tersebut; dan Relationships menunjukkan posisi entri di pohon kelemahan. Untuk pekerjaan harian, mulailah dari Mitigations fase Implementation; naik ke Architecture bila masalah berulang di banyak tempat.

Lima Kerentanan yang Paling Sering Muncul di C++ #

Lima ID berikut menduduki puncak daftar kerentanan kode C dan C++ selama bertahun-tahun — dan semuanya sudah kita bedah di section ini:

IDNama resmiWujud khas di C++Mitigasi inti
CWE-120Buffer Overflowsalinan ke char[N] tanpa batasstd::string, batas dari size(), snprintf
CWE-787Out-of-bounds Writev[i] = x dengan i dari luarcek batas, at(), batas dari container
CWE-416Use After Freeakses setelah deleteunique_ptr/shared_ptr, satu pemilik
CWE-476NULL Pointer Dereferencedereferensi pointer kosongperiksa sebelum pakai; minimalkan pointer mentah
CWE-190Integer Overflowukuran hasil hitungan meluapperiksa sebelum operasi, builtin overflow

Setiap baris tabel menunjuk ke chapter yang membahasnya secara penuh — buffer-overflow, out-of-bounds-access, use-after-free, dan integer-overflow-dan-konversi. Chapter ini menyambungkannya menjadi satu peta yang memakai nama baku.

Demonstrasi Mitigasi dalam Satu Program #

Program berikut menjalankan satu mitigasi untuk setiap ID di tabel — bukan versi rentannya; wujud rentan sudah kita lihat di chapter masing-masing:

cpp
// mitigasi.cpp — satu pola mitigasi untuk setiap CWE yang paling sering muncul di C++.

#include <iostream>
#include <memory>
#include <vector>

int main() {
    // CWE-476 (null pointer dereference): periksa sebelum dereferensi.
    int* mungkinKosong = nullptr;
    if (mungkinKosong != nullptr) {
        std::cout << "CWE-476: nilai " << *mungkinKosong << "\n";
    } else {
        std::cout << "CWE-476: pointer kosong diperiksa, tidak dereferensi\n";
    }

    // CWE-190 (integer overflow): aritmetika diperiksa, hasil hanya bila aman.
    int besar = 2'000'000'000;
    int hasil = 0;
    if (__builtin_add_overflow(besar, besar, &hasil)) {
        std::cout << "CWE-190: penjumlahan meluap, operasi ditolak\n";
    }

    // CWE-787 / CWE-120 (out-of-bounds write / buffer overflow): batas dari container.
    std::vector<int> data = {1, 2, 3};
    std::size_t indeks = 9;
    if (indeks < data.size()) {
        data[indeks] = 0;
    } else {
        std::cout << "CWE-787: indeks " << indeks << " di luar batas, penulisan ditolak\n";
    }

    // CWE-416 (use-after-free): kepemilikan otomatis, pelepasan tunggal, cek setelahnya.
    auto pemilik = std::make_unique<int>(7);
    std::cout << "CWE-416: nilai via unique_ptr = " << *pemilik << "\n";
    pemilik.reset();
    std::cout << "CWE-416: setelah reset, pemilik == nullptr? "
              << std::boolalpha << (pemilik == nullptr) << "\n";
    return 0;
}

Output yang Dihasilkan:

text
CWE-476: pointer kosong diperiksa, tidak dereferensi
CWE-190: penjumlahan meluap, operasi ditolak
CWE-787: indeks 9 di luar batas, penulisan ditolak
CWE-416: nilai via unique_ptr = 7
CWE-416: setelah reset, pemilik == nullptr? true

Bedah baris-per-baris:

  1. Baris 9–14 (CWE-476) — pointer diuji sebelum dereferensi dan cabang else membuat jalur “tidak ada objek” terlihat di output; kebiasaan yang lebih kuat lagi adalah meminimalkan pointer mentah yang bisa kosong — pakai referensi atau nilai bila objek selalu ada.
  2. Baris 17–21 (CWE-190) — __builtin_add_overflow (GCC dan Clang) menjumlahkan sekaligus melaporkan luapan dalam satu panggilan; hasil yang meluap tidak pernah dipakai. Chapter integer-overflow-dan-konversi membahasnya lebih dalam.
  3. Baris 24–30 (CWE-787 dan CWE-120) — batas diambil dari container itu sendiri (indeks < data.size()), bukan dari konstanta yang diketik terpisah; penulisan di luar batas ditolak dengan pesan.
  4. Baris 33–37 (CWE-416) — std::make_unique menjadikan pemilik satu-satunya pemilik; setelah reset(), statusnya bisa diperiksa tanpa mendereferensi. Akses setelah pelepasan berubah dari UB menjadi keputusan yang terlihat.

CWE-120 tidak punya baris tersendiri karena mitigasinya memang gabungan: batas yang diambil dari container seperti CWE-787, plus container yang mengelola ukurannya sendiri — persis kebiasaan std::string dan std::vector yang dipakai sepanjang section ini.

Mitigasi Berlapis: Tidak Ada Lapis Tunggal #

Satu lapis tidak pernah cukup. Program di atas menumpuk lapisan bahasa (container, smart pointer), lapisan pemeriksaan eksplisit (batas, nullptr), dan lapisan aritmetika aman; di atasnya masih ada lapisan alat: -Wall -Wextra saat kompilasi, static analysis, dan sanitizer pada build uji — semuanya sudah kita pegang di section Debugging dan Code Quality. Lapisan berbeda menangkap kesalahan yang berbeda: compiler menangkap yang statis, sanitizer yang dinamis, review yang kontekstual. Ketika semuanya berjalan, laporan keamanan pun punya bahasanya: tiap temuan dicatat dengan ID CWE, ditutup dengan mitigasi yang bisa diverifikasi, dan dicek ulang di rilis berikutnya.

Kamus CWE memberi nama baku pada masalah, dan nama baku memungkinkan tim bicara, memprioritaskan, dan mengukur. Chapter terakhir section ini mengubah seluruh kebiasaan yang kita kumpulkan menjadi dokumen kerja harian: coding guidelines.

Referensi: MITRE — CWE List , MITRE — CWE-787: Out-of-bounds Write .