FlawOpen

flawopen.com/Keamanan memori/strcpy vs strncpy

Apakah strncpy() lebih aman daripada strcpy()?

CWE-787: penulisan di luar batas; CWE-170: terminasi null yang tidak tepatHalaman referensi
Jawaban singkat

Field berukuran tetap seperti deretan slot berlabel: slot terakhir harus menyimpan penanda akhir jika kode berikutnya memperlakukan byte sebagai string C. strncpy() menulis paling banyak n byte dan hanya mencegah penulisan melewati tujuan jika n tidak melebihi kapasitas buffer sebenarnya. Jika sumber memenuhi batas tersebut, terminator null tidak ditambahkan. Fungsi string berikutnya dapat membaca melewati tujuan saat mencari penanda yang hilang.

KEDUANYA KELIRU
char dst[16];

/* 1. Unbounded — classic overflow */
strcpy(dst, src);

/* 2. Bounded, but may not terminate.
   If strlen(src) >= 16, dst has no
   '\0' and every later strlen/printf
   reads out of bounds.            */
strncpy(dst, src, sizeof(dst));

/* 3. Off-by-one: room for 16 chars
   plus a terminator = 17 bytes,
   but dst only holds 16.          */
strncpy(dst, src, sizeof(dst));
dst[sizeof(dst)] = '\0';   /* OOB! */
BENAR
char dst[16];

/* Preferred: snprintf always
   null-terminates (when size > 0),
   and tells you about truncation. */
int n = snprintf(dst, sizeof(dst),
                 "%s", src);
if (n < 0 || (size_t)n >= sizeof(dst)) {
    /* truncated — handle it */
    return ERR_TOO_LONG;
}

/* Or strlcpy where available —
   always terminates, returns the
   length it tried to create.      */
if (strlcpy(dst, src, sizeof(dst))
        >= sizeof(dst)) {
    return ERR_TOO_LONG;
}

Tujuan awal strncpy

Perilaku ini bukan cacat: strncpy() dirancang untuk field karakter berukuran tetap yang diisi null, bukan sebagai penyalinan string C yang aman untuk semua kebutuhan. Jika string sumber lebih pendek dari n, fungsi mengisi tujuan dengan byte null hingga n - 1. Jika tidak ada byte null dalam n byte pertama sumber, fungsi menyalin tepat n byte dan tidak mengakhiri tujuan. Ini cocok untuk beberapa format field tetap, tetapi berbahaya jika hasilnya diberikan ke API yang mengharapkan string berterminator null.

Jika sumber lebih pendek daripada n, padding wajib menulis sampai seluruh lebar field. Pada buffer besar dan sumber pendek, ini dapat melakukan lebih banyak pekerjaan daripada fungsi yang berhenti di terminator.

Selalu periksa pemotongan

Mencegah overflow baru separuh pekerjaan. Pemotongan diam-diam juga berisiko: hostname, path, atau nilai otorisasi yang terpotong dapat berubah makna. snprintf mengembalikan panjang yang ingin ditulis; bandingkan dengan ukuran buffer. Salah membaca nilai ini sebagai jumlah byte yang benar-benar ditulis juga relevan pada Citrix Bleed.

Pertanyaan umum

Bagaimana dengan strcpy_s dan fungsi Annex K?

Fungsi tersebut mengakhiri string dan memeriksa batas, tetapi portabilitasnya tidak merata: dukungan baik di Windows dan implementasi yang beragam di tempat lain. Untuk banyak platform, snprintf biasanya lebih tersedia.

Apakah strlcpy bagian dari standar C?

Tidak. Fungsi ini berasal dari OpenBSD dan tersedia luas di BSD serta macOS; glibc versi baru juga menambahkannya. Periksa ketersediaannya pada target Anda.

Di C++, apakah saya perlu memakai fungsi-fungsi ini?

Utamakan std::string dan std::string_view yang mengelola panjang. Gunakan fungsi C hanya pada batas API yang mensyaratkan buffer mentah.

Referensi

Lihat juga CWE vs CVE: apa bedanya? Mass Assignment: risiko dan allowlist field yang aman Kebocoran state serverless: isolasi data per permintaan PHP == dan perbandingan Magic Hash Apakah blok unsafe Rust tetap aman bagi memori?