,

C’de Kullandığınızda Başınızı Ağrıtabilecek 8 Fonksiyon

C programlama dili, hem yeni başlayanlar hem de orta seviyedeki geliştiriciler için temel bir yapı taşıdır. Sistem programlamasından oyun geliştirmeye kadar geniş bir kullanım alanına sahip olan bu dil, düşük seviyeli bellek yönetimi ve yüksek performans gerektiren uygulamalarda sıkça tercih edilir. C dilini öğrenmek, yalnızca bu dile hâkim olmanızı sağlamakla kalmaz, aynı zamanda diğer programlama dillerini anlamanızı ve algoritma mantığınızı geliştirmenizi kolaylaştırır. Bu yazıda, C dilindeki bazı tehlikeli fonksiyonları ele alacağız.

C programlama dilinde bazı fonksiyonlar, güvenlik açıklarına veya bellek hatalarına neden olabilecek riskler taşır. İşte kullanmaktan kaçınılması gereken bazı fonksiyonlar ve neden olduğu problemler:

1. gets()

  1. Neden tehlikelidir?
    • Kullanıcıdan alınan girdiyi doğrudan bir diziye (array) yazar. Ancak, girilen verinin uzunluğunu kontrol etmez.
    • Bellek taşması (buffer overflow) riskine neden olur.
    • Uzun bir girdi, belleğin taşmasına neden olarak programı çökertir veya hacker’lar kod enjeksiyonu (buffer overflow exploit) yaparak sistemde kötü niyetli işlemler gerçekleştirebilir.

📌Nasıl Olur?

Kullanıcıdan alınan kontrolsüz girdi, bellekte kritik alanları (örneğin geri dönüş adreslerini) ezerek program akışını değiştirebilir. Bu, saldırganların kötü amaçlı kod çalıştırmasına olanak tanır.

Örnek Senaryo:

  • Kullanıcıdan 10 karakterlik bir dizi alınması beklenirken, 100 karakter girilirse, bu fazla karakterler bellek düzenini bozar.
  • Bu bozulma, saldırganların programın kontrolünü ele geçirmesine yol açabilir (örneğin, sistemde komut çalıştırma veya arka kapı açma).

Alternatif:

  • fgets() kullanın (Girdi uzunluğunu sınırlandırabilir ve taşmayı önler).

📌 Örnek:

char buffer[50];
gets(buffer); // TEHLİKELİ!

Doğrusu:

fgets(buffer, sizeof(buffer), stdin); // GÜVENLİ

2. strcpy() ve strcat()

  • Neden tehlikelidir?
    • Hedef bellek bölgesinin boyutunu kontrol etmez, bu da taşmaya yol açabilir.
  • Alternatif:
    • strncpy() ve strncat() kullanın (Sınırlandırılmış kopyalama ve birleştirme yapar).

📌 Örnek:

char dest[10];
char *src = "UzunMetin";
strcpy(dest, src); // TEHLİKELİ!

Doğrusu:

strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // Sonlandırıcı ekleyin

3. sprintf()

  • Neden tehlikelidir?
    • Formatlı çıktı oluştururken taşmaya neden olabilir.
  • Alternatif:
    • snprintf() kullanın (Çıkışın uzunluğunu kontrol eder).

📌 Örnek:

char buffer[50];
sprintf(buffer, "Merhaba %s", isim); // TEHLİKELİ!

Doğrusu:

snprintf(buffer, sizeof(buffer), "Merhaba %s", isim); // GÜVENLİ

4. scanf()

  • Neden tehlikelidir?
    • Girdide sınır kontrolü yapılmaz, fazla veri girildiğinde bellek taşması oluşur.
  • Alternatif:
    • fgets() ile sscanf() kombinasyonu kullanın.

📌 Örnek:

char isim[20];
scanf("%s", isim); // TEHLİKELİ!

Doğrusu:

fgets(isim, sizeof(isim), stdin);

5. malloc() ve free()

  • Neden dikkatli kullanılmalı?
    • Yanlış boyutta bellek tahsisi veya çift serbest bırakma (double free) hatalarına neden olabilir.
  • Öneri:
    • calloc() kullanın (Belleği sıfırlar ve taşmayı engeller).
    • free() kullanırken çift serbest bırakmaktan kaçının.

📌 Örnek:

char *p = malloc(10);
free(p);
free(p); // HATA: Çift free!

Doğrusu:

char *p = calloc(10, sizeof(char));
free(p);
p = NULL; // Çift free'yi önler

6. atoi()

  • Neden tehlikelidir?
    • Geçersiz girdi için hata kontrolü yapmaz (örneğin, “abc” girdiğinde 0 döndürür).
  • Alternatif:
    • strtol() kullanın (Hataları tespit edebilir).

📌 Örnek:

int sayi = atoi("abc"); // TEHLİKELİ!

Doğrusu:

char *endptr;
int sayi = strtol("123abc", &endptr, 10);
if (*endptr != '\0') {
    printf("Geçersiz sayı!\n");
}

Özetlersek,

Tehlikeli FonksiyonGüvenli AlternatifNeden Kaçınılmalı?
gets()fgets()Bellek taşmasına neden olabilir.
strcpy(), strcat()strncpy(), strncat()Sınır kontrolü yapılmaz, taşma olabilir.
sprintf()snprintf()Formatlı çıkışta taşma riski vardır.
scanf()fgets() + sscanf()Girdi kontrolü yoktur, bellek taşması olur.
malloc()calloc()Yanlış kullanımda bellek hataları oluşur.
atoi()strtol()Geçersiz girdide hata kontrolü yapmaz.

Bu fonksiyonlar özellikle büyük ve güvenlik odaklı projelerde güvenlik açığına yol açabileceği için dikkatli kullanılmalı veya güvenli alternatifleri tercih edilmelidir.

📚 Hangi Standartlar Bu Fonksiyonları Düzenler?

Bu tür fonksiyonların kullanımıyla ilgili öneriler genellikle programlama standartları ve güvenlik rehberleri tarafından belirlenir. Ancak, bu fonksiyonlar tamamen yasak değildir; bazı durumlarda dikkatli ve doğru kullanıldığında işe yarayabilirler. İşin özü: Bağlama ve projeye bağlı olarak değişir.

Bu tür fonksiyonların güvenli olmayan kabul edilmesi ve alternatif önerilmesi, genellikle aşağıdaki endüstri standartlarına dayalıdır:

  1. C Standartları:
    • ISO/IEC 9899:2018 (C17) – En güncel C standardı.
    • C11 (ISO/IEC 9899:2011) – Güvenli alternatifler için *_s (secure) fonksiyonlarını tanıtır.
  2. Güvenlik Odaklı Standartlar:
    • CERT C Coding Standard – Carnegie Mellon tarafından geliştirilen bu standart, özellikle güvenli olmayan C fonksiyonlarından kaçınılmasını önerir.
    • MISRA C (Motor Industry Software Reliability Association) – Otomotiv sektörü için kullanılan bir standarttır; güvenlik açısından kritik yazılımlar için katıdır.
    • CWE (Common Weakness Enumeration) – Bellek taşması, çift serbest bırakma (double-free) gibi zafiyetleri tanımlar.
  3. Diğer Öneriler ve Kılavuzlar:
    • Microsoft Security Development Lifecycle (SDL) – Windows geliştirme sürecinde güvenli kodlama rehberidir.
    • Open Web Application Security Project (OWASP) – Web uygulamaları için riskli işlemleri ve güvenli alternatifleri belirler.

⚠️ Bu Fonksiyonlar Asla Kullanılmamalı mı?

Duruma göre değişir! Bazı durumlarda bu fonksiyonlar güvenle kullanılabilir, ancak aşağıdaki faktörlere dikkat etmek gerekir:

Ne Zaman Kaçınmalıyız?

  • Güvenlik Kritiktir: Finans, sağlık, askeri veya kişisel veriler işleyen sistemlerde bu tür fonksiyonlar risk taşır.
  • Kullanıcı Girdisi İşliyorsanız: gets(), scanf() gibi fonksiyonlar, kontrolsüz kullanıcı girişi nedeniyle tehlikelidir.
  • Geniş ve Karmaşık Projelerde: Güvenli olmayan fonksiyonlar bakım sorunlarına ve hata ayıklamaya zorluk çıkarabilir.

Ne Zaman Kullanılabilir?

  • Performans Önemliyse: Bazı güvenli alternatifler (örneğin, snprintf()), klasik sprintf()ye göre daha yavaş olabilir. Performans kritikse dikkatlice değerlendirilebilir.
  • Kapalı Sistemlerde: Kullanıcıdan doğrudan girdi alınmayan ve dış dünyayla sınırlı etkileşimi olan sistemlerde (örneğin gömülü sistemler) kontrollü biçimde kullanılabilir.
  • Hızlı Prototipleme: Hızlı geliştirme süreçlerinde bazen karmaşıklık eklememek adına kullanılabilir, ancak üretime geçmeden önce gözden geçirilmelidir.

İşte bazı örnek durumlar ve kararlar:

DurumTehlikeli FonksiyonKullanım Durumu
Web sunucusunda kullanıcı giriş işlemigets()❌ Asla kullanılmamalı.
Gömülü sistemde sabit uzunlukta dizi kopyalamastrcpy()✅ Dikkatli ve kontrollü kullanılabilir.
Matematiksel hesaplama için formatlamasprintf()✅ Performans nedeniyle tercih edilebilir.
Yüksek güvenlikli bankacılık uygulamasıatoi()❌ Yerine strtol() kullanılmalı.
Hızlı test için basit girdi okumascanf()✅ Kontrollü ve dikkatli kullanılabilir.

Önerilen Yaklaşım:

  1. Güvenlik Öncelikli ProjelerdeGüvenli Alternatifler Kullanın
  2. Performans Kritik ve Kontrollü OrtamlardaKlasik Fonksiyonlar Kullanılabilir
  3. Kod İncelemelerindeRiskli Fonksiyonların Kullanımını Belgelerle Gerekçelendirin

Öneri: Eğer bir proje üzerinde çalışıyorsanız, ilgili standart ve rehberlere bağlı kalmak uzun vadede güvenli ve sürdürülebilir bir kod tabanı sağlar.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

tr_TRTR