Belajar C++ - Secure Coding & Safety
Series/Belajar C++/Episode 14
Episode 14 of 24

Belajar C++ - Secure Coding & Safety

Episode ini membahas keamanan kode C++: memory safety dan mitigasi buffer overflow, penggunaan aman C string API dibanding std::string, input validation dengan boundary checks, serta cybersecurity best practices untuk aplikasi produksi.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Pendahuluan

C++ memberi kalian kontrol penuh atas memori — dan kontrol penuh berarti kesalahan kecil bisa menjadi celah keamanan yang parah. Sebagian besar kerentanan di aplikasi C/C++ berakar pada pengelolaan memori yang salah: buffer overflow, use-after-free, dan format string yang tidak aman.

Episode 14 mengajarkan secure coding: mengapa buffer overflow terjadi dan bagaimana mencegahnya, mengapa std::string lebih aman daripada array char[], cara memvalidasi dan mensanitasi input, mitigasi yang disediakan compiler, serta best practices cybersecurity yang diterapkan di industri.

Memory Safety dan Buffer Overflow

Anatomi Buffer Overflow

Buffer overflow terjadi saat program menulis lebih banyak data daripada kapasitas buffer. Data meluap ke memori di sekitarnya, dan penyerang bisa memanfaatkannya untuk menimpa alamat kembali fungsi atau menjalankan kode sendiri. Contoh klasik:

Kode rentan overflow
cat > rentan.cpp <<'EOF'
#include <iostream>
#include <cstring>
 
int main() {
    char nama[8];
    std::cout << "Masukkan nama: ";
    std::cin >> nama;
    std::cout << "Halo " << nama << "\n";
}
EOF
g++ -std=c++20 rentan.cpp -o rentan

std::cin >> nama menulis ke buffer char nama[8] tanpa memeriksa panjang input. Jika pengguna mengetik lebih dari 7 karakter, data meluap dan menimpa memori lain — undefined behavior yang bisa menjadi kerentanan. Kode seperti ini tidak boleh muncul di produksi.

Prinsip Memory Safety

Aturan utama: jangan pernah membiarkan data masuk ke buffer tanpa memeriksa ukuran. Gunakan tipe yang tahu panjangnya sendiri. std::string, std::vector, dan kontainer STL mengelola batasnya secara otomatis, sehingga overflow tidak mungkin terjadi lewat API normal.

Hindari C String API

strcpy dan kawan-kawan

Fungsi C klasik strcpy, strcat, sprintf, dan gets tidak memeriksa batas tujuan. gets bahkan sudah dihapus dari standar C karena tidak mungkin dipakai aman. Ganti semuanya dengan std::string dan std::string_view:

Salah dan benar
cat > aman.cpp <<'EOF'
#include <iostream>
#include <string>
 
int main() {
    const char* raw = "teks panjang melebihi buffer";
    char buffer[8];
 
    // strcpy(buffer, raw);  // overflow!
 
    std::string aman = raw;
    std::cout << "Panjang: " << aman.size() << "\n";
    std::cout << aman << "\n";
}
EOF
g++ -std=c++20 aman.cpp -o aman
./aman

std::string aman = raw menyalin string dengan ukuran yang dikelola sendiri — aman tanpa memikirkan batas buffer. std::string_view memberikan tampilan non-owning ke string yang sama, berguna untuk parameter fungsi tanpa menyalin.

Format String yang Aman

printf klasik membawa risiko format string vulnerability: jika format diterima dari pengguna, penyerang bisa membaca dan menulis memori lewat specifier seperti %x dan %n. Jangan pernah melempar input pengguna langsung ke printf. Di C++20, std::format adalah pengganti yang aman:

Format aman
#include <format>
// std::print("Nama: {}\n", nama);  // C++23, format aman

std::format("Nama: {} ...)" memisahkan format dari argumen dan memvalidasi keduanya saat kompilasi, menghilangkan seluruh kelas bug format.

Input Validation dan Boundary Checks

Validasi Sebelum Memproses

Semua input yang datang dari luar — pengguna, jaringan, file — tidak bisa dipercaya. Validasi dulu sebelum dipakai: panjang, rentang, dan format:

Validasi input
cat > validasi.cpp <<'EOF'
#include <iostream>
#include <string>
#include <cctype>
 
bool valid_umur(const std::string& s) {
    if (s.empty() || s.size() > 3) return false;
    for (char c : s) {
        if (!std::isdigit(c)) return false;
    }
    return true;
}
 
int main() {
    std::string input;
    std::cin >> input;
 
    if (valid_umur(input)) {
        int umur = std::stoi(input);
        std::cout << "Umur valid: " << umur << "\n";
    } else {
        std::cerr << "Input tidak valid\n";
    }
}
EOF
g++ -std=c++20 validasi.cpp -o validasi
./validasi

valid_umur(s) memeriksa input kosong, panjang maksimal, dan bahwa semua karakter adalah digit sebelum mengonversinya. Pola ini — validasi sebelum konversi — mencegah std::stoi melempar atau menghasilkan nilai di luar ekspektasi.

Boundary Checks pada Kontainer

Saat mengakses elemen kontainer dengan indeks yang mungkin tidak valid, pakai at() yang melempar std::out_of_range, bukan operator[] yang tanpa pemeriksaan. Untuk iterasi, range-based for dan iterator menghilangkan kebutuhan indeks manual sama sekali — dan dengan itu, kebutuhan boundary check.

Mitigasi dan Tooling Keamanan

Mitigasi di Compiler

Compiler modern menyediakan mitigasi yang bisa diaktifkan lewat bendera: PIE (-fPIE) untuk address space randomization, stack protector (-fstack-protector-strong) untuk mendeteksi corupsi stack, dan Fortify (-D_FORTIFY_SOURCE=2) untuk memeriksa buffer pada fungsi libc:

Build dengan mitigasi
g++ -std=c++20 -fstack-protector-strong -D_FORTIFY_SOURCE=2 \
    -Wl,-z,relro,-z,now app.cpp -o app

Bendera -fstack-protector-strong memasang canary untuk mendeteksi overflow stack, dan -Wl,-z,relro,-z,now membuat segmen GOT read-only setelah linking. Kombinasikan semua ini di build release untuk mempersulit eksploitasi.

Sanitizer dan Analisis

Gunakan AddressSanitizer dan UndefinedBehaviorSanitizer selama pengembangan untuk menangkap bug sebelum dirilis. -fsanitize=address,undefined mendeteksi overflow, use-after-free, dan perilaku undefined lainnya. Di CI, tambahkan static analysis clang-tidy dengan pemeriksaan keamanan. Episode 11 dan 19 akan memperdalam kedua hal ini.

Warning

Mitigasi compiler menaikkan biaya eksploitasi, bukan menghilangkan bug. Pengganti utama tetap kode yang aman: std::string, boundary checks, dan validasi input.

Cybersecurity Best Practices

Prinsip yang Harus Dipegang

Beberapa prinsip keamanan yang berlaku universal di kode C++:

  • Least privilege: berikan proses hanya izin yang dibutuhkan.
  • Fail closed: jika validasi gagal, tolak — jangan lanjutkan dengan asumsi.
  • Defense in depth: kombinasi validasi, sanitizer, mitigasi, dan review.
  • Jangan menulis sendiri: gunakan library teruji untuk kriptografi dan parsing.
  • Sanitasi data: jangan menampilkan atau menyimpan input mentah tanpa penanganan.

Sanitasi berarti membersihkan input dari karakter atau struktur yang berbahaya sebelum dipakai — misalnya menghindari injection saat membangun query atau log. Di C++, hindari membuat string eksekusi dinamis; pilih mekanisme terstruktur.

Penutup

Inti yang harus dibawa pulang:

  • Buffer overflow terjadi saat menulis melebihi kapasitas buffer tanpa pemeriksaan.
  • Gunakan std::string, std::string_view, dan kontainer STL alih-alih array mentah.
  • Hindari strcpy, strcat, sprintf, dan gets.
  • Validasi dan sanitasi semua input sebelum diproses.
  • Aktifkan stack protector, PIE, dan Fortify di build produksi.
  • Defense in depth: validasi, sanitizer, mitigasi, dan library teruji.

Di episode 15 selanjutnya kita akan membahas performance dan optimization — profiling dengan perf dan Valgrind, optimasi memory layout dan cache friendliness, compiler optimization flags, inline dan loop unrolling, serta tradeoff antara readability dan performance.

Belajar C++ - Secure Coding & Safety | Belajar C++