Yazılımcı gözünden KVKK

6698 sayılı Kişisel Verilerin Korunması Kanunu (KVKK) 2016'dan beri yürürlükte ama hâlâ birçok ekip, yasayı hukuk ekibinin sorunu olarak görüyor. Gerçek şu: yazılım mimarisi kararlarının çoğu — hangi alanı loglarsın, ne kadar süre saklarsın, kime API erişimi verirsin, test ortamına hangi veriyi koyarsın — doğrudan KVKK uyumuna girer. Hukuk ekibi sadece sözleşme ve aydınlatma metnini yönetir; teknik uygulama mühendisin sorumluluğundadır.

Bu yazı, Türkiye'de TC kimlik doğrulaması yapan bir yazılım ekibinin KVKK açısından bilmesi gereken temelleri işliyor: Türkiye Cumhuriyeti Kimlik Numarası'nın (TCKN) hangi veri kategorisine girdiği, nerede ve ne kadar saklanabileceği, log ve metrik politikalarının nasıl kurulacağı, anonim test verisi üretimi ve aydınlatma metninin yazılımcı odaklı kontrol listesi.

Hukuki tavsiye değildir. Hukuk departmanınızla mutlaka doğrulayın. Ancak aşağıdaki pratikler çoğu denetimde karşılaşılan teknik bulguların önüne geçer.

TC kimlik (TCKN) ve VKN: aynı kefede değiller

KVKK'nın 3. maddesi "kişisel veri"yi "kimliği belirli veya belirlenebilir gerçek kişiye ilişkin her türlü bilgi" olarak tanımlar. TC kimlik numarası bir gerçek kişiyi tek başına tanımlar — dolayısıyla kişisel veridir. Üstelik Kişisel Verileri Koruma Kurulu'nun (KVKK Kurulu) kararları TCKN'yi zaman zaman "özel nitelikli olmayan ama yüksek risk taşıyan" kategoride değerlendirir.

VKN ise tüzel kişiliklere aittir. Tüzel kişilikler KVKK'nın koruma kapsamında değildir (KVKK, sadece gerçek kişileri korur). Yani bir şirketin VKN'sini log'da tutmak KVKK açısından ihlal oluşturmaz. Ancak şu istisna önemlidir: şahıs şirketlerinde VKN yerine TCKN kullanılır; bu durumda log'daki "vkn" alanı aslında gerçek kişinin TCKN'si olabilir. Uygulamanız bu ayrımı yapabiliyor olmalı.

Pratik çıkarım: TCKN'ye uygulanan politikaların büyük kısmı VKN'ye uygulanmaz. Ancak aynı alan tipinde taşınıyorsa (örneğin customer_identifier kolonu TCKN de VKN de kabul ediyor), muhafazakâr davranıp en katı politikayı uygulayın.

VKN'nin yapısal detayları için VKN yapısı ve doğrulama yazımıza göz atın.

Hukuki işleme sebebi: rıza her zaman doğru cevap değil

KVKK madde 5, işlemeyi ilgili kişinin açık rızasına bağlar (m.5/1); m.5/2 ise açık rıza aranmayan halleri yedi bent hâlinde sayar. Yani toplamda sekiz hukuki sebep vardır:

BentHukuki sebep
m.5/1Açık rıza
m.5/2-aKanunlarda açıkça öngörülme
m.5/2-bFiili imkânsızlık nedeniyle rızasını açıklayamayacak durumdaki kişinin hayatı veya beden bütünlüğünün korunması
m.5/2-cBir sözleşmenin kurulması veya ifasıyla doğrudan ilgili olması
m.5/2-çVeri sorumlusunun hukuki yükümlülüğünü yerine getirmesi
m.5/2-dİlgili kişinin kendisi tarafından alenileştirilmiş olması
m.5/2-eBir hakkın tesisi, kullanılması veya korunması için zorunlu olması
m.5/2-fVeri sorumlusunun meşru menfaati (temel hak ve özgürlüklere zarar vermemek kaydıyla)

Kalın yazılan iki bent, geliştirici rehberlerinde en sık atlananlardır. Özellikle alenileştirme (m.5/2-d), şirket ünvanı ve VKN gibi kamuya açık edilmiş verileri işlerken dayanılan sebeplerden biridir.

"Açık rıza" bunlardan yalnızca biridir ve pratikte en kırılganıdır — kullanıcı her an geri çekebilir ve geri çekildiğinde işlemeyi durdurmak zorundasınızdır. Elinizde başka bir hukuki sebep varken rızaya dayanmak, kendinize gereksiz bir kırılganlık eklemektir.

TC kimlik doğrulaması yapıyorsanız, doğru hukuki sebep genelde "sözleşmenin kurulması" veya "kanunlarda öngörülme"dir:

  • Banka/ödeme kuruluşu → MASAK düzenlemesi gereği (kanuni yükümlülük)
  • E-ticaret kaydı → sözleşmenin kurulması (müşteri kimliği gerekli)
  • Sigorta teklifi → meşru menfaat + sözleşme öncesi
  • Pazarlama amaçlı → açık rıza (ayrı ve geri çekilebilir)

Bu, aydınlatma metninizdeki "hukuki sebep" alanının doğru doldurulmasını etkiler ve DevOps tarafında retention policy'yi belirler.

Log ve telemetri: en sık ihlal noktası

Denetimlerde en sık bulunan teknik ihlal, TC kimlik numarasının uygulama loglarına düşmesidir. Üç klasik senaryo:

  1. HTTP erişim loglarına query string olarak TCKN gider. /api/user?tckn=12345678901 yanlıştır; POST + body kullanın, TCKN'yi URL'de taşımayın.
  2. Error stack trace'lerinde request body dump edilir ve TCKN de oraya düşer. Sentry, Datadog, New Relic gibi APM araçlarında PII scrubbing kurallarını mutlaka aktif edin.
  3. SQL query loglarında WHERE tckn = '12345678901' açıkça görülür. pg_stat_statements veya slow query log'u parametreleri maskelemeli.

Pratik çözüm: uygulama log'unda TC kimlik no asla tam haliyle yer almamalı. Maskelenmiş bir formatta tutulabilir:

function maskTckn(t) {
  if (typeof t !== 'string' || t.length !== 11) return '***';
  return t.slice(0, 3) + '****' + t.slice(-2);
}
// "12345678901" -> "123****01"

Bu, destek ekibinin "bu TCKN'yi logda görebiliyor musun" tarzı taleplerinde bile yeterli olur. Tam TCKN'ye ihtiyaç olursa, sadece audit log'larda ve şifreli tutulmalı.

Log saklama süresi

KVKK Kurulu kararları "veri, işleme amacı için gereken süre kadar saklanır" demekle yetinir; spesifik süre vermez. Pratik saha normları:

  • HTTP erişim log'u: 7–30 gün
  • Uygulama log'u: 30–90 gün
  • Audit log'u (compliance gereği): 2–10 yıl, ama erişim kısıtlı ve şifreli

Bankacılık/sigorta gibi düzenlemeye tâbi sektörlerde BDDK/SPK kuralları KVKK'dan daha uzun saklama şart koşabilir. Hukuk ekibinizin sektör regülasyonunu doğrulaması şart.

Veritabanı: şifreleme ve erişim

TC kimlik numarası tutan kolonlar için şu katmanları düşünün:

  • At-rest encryption: PostgreSQL için TDE veya volume-level encryption (LUKS, AWS KMS). Minimum şart.
  • Application-level encryption: hassas alanları (TCKN, IBAN) bir HSM/KMS anahtarıyla şifreleyip DB'ye şifrelenmiş yazmak. Arama yapılacaksa deterministik şifreleme veya hash tabanlı indeks.
  • Row-level security: kullanıcının kendi satırlarına erişimi. PostgreSQL RLS kullanışlı.
  • Audit trigger: SELECT'leri de loglayan tetikleyici. Denetim için kritik.

TCKN'yi cleartext index'le tutmak hatalı değildir ama ideal de değildir. Orta yol: aramaları ayrı bir tckn_lookup kolonu üzerinden yapmak, gerçek değeri şifreli saklamak.

Ama bu kolonu kurarken iki tuzağa dikkat edin — çoğu rehber ikisini de atlıyor:

  1. Aranabilirlik, salt'ın sabit olmasını zorunlu kılar. Satır başına rastgele salt kullanırsanız WHERE tckn_lookup = ? zaten çalışmaz. Yani "salt'lı hash" önerisi, pratikte ancak tek ve sabit bir gizli değerle işler — güvenliğiniz tamamen o tek değerin gizliliğine bağlıdır.
  2. Anahtar uzayı küçüktür. Geçerli TCKN sayısı 10⁹ mertebesindedir. Bu, modern donanımda tüm uzayın kaba kuvvetle taranabileceği anlamına gelir. Sabit gizli değer sızarsa saldırgan tek geçişte tüm tabloyu geri çevirir; "hash'lediğimiz için güvende" güvencesi bu boyutta karşılanmaz.

Doğru kurgu: düz SHA-256 yerine anahtarı veritabanının dışında (KMS/HSM) tutulan bir HMAC kullanın. Böylece veritabanı dökümü tek başına yeterli olmaz; saldırganın ayrıca anahtar yönetim sistemine erişmesi gerekir. Anahtar rotasyonunu da baştan planlayın — rotasyon, lookup kolonunun yeniden hesaplanmasını gerektirir.

Cross-border transfer (veri yurtdışı aktarımı)

Bu bölüm 2024'te değişti. 7499 sayılı Kanun ile KVKK madde 9 yeniden yazıldı ve değişiklik 1 Haziran 2024'te yürürlüğe girdi. Eski "her aktarım için kural olarak Kurul izni" anlatımı artık geçerli değildir; yerine üç basamaklı, GDPR'daki yapıya benzer bir mekanizma geldi:

  1. Yeterlilik kararı. Aktarımın yapılacağı ülke, o ülkedeki sektör veya uluslararası kuruluş hakkında Kurul'un yeterlilik kararı varsa, m.5/m.6 şartlarından biri de sağlanmak kaydıyla aktarım yapılabilir.
  2. Uygun güvenceler. Yeterlilik kararı yoksa; ilgili kişinin aktarım yapılacak ülkede de haklarını kullanma ve etkili kanun yollarına başvurma imkânı bulunmak kaydıyla, taraflarca uygun güvencelerden biri sağlanarak aktarım yapılabilir (standart sözleşme, bağlayıcı şirket kuralları, taahhütname vb.). Standart sözleşme kullanıldığında imzadan itibaren beş iş günü içinde Kurum'a bildirim yükümlülüğü vardır.
  3. Arızi haller. İlk iki basamağın hiçbiri sağlanamıyorsa, kanunda sayılan istisnai durumlarda ve arızi olmak kaydıyla aktarım mümkündür. Buradaki "arızi" kelimesi kritik: süreklilik arz eden bir veri akışını bu basamağa dayandıramazsınız.

Yazılımcı açısından pratik karşılığı:

  • TCKN'yi ABD'deki bir APM/log servisine göndermek risklidir. PII scrubbing şart; en iyisi TCKN'nin o sistemlere hiç ulaşmamasıdır.
  • AWS eu-central-1 yerine us-east-1 kullanıyorsanız veri yurt dışına gidiyor demektir. Hangi basamağa dayandığınızı yazılı olarak bilmelisiniz.
  • Cloudflare, Sentry, Slack gibi SaaS araçlarında veri işleme sözleşmesi (DPA) imzalayın ve veri akış haritası tutun. Denetimde ilk sorulan şey budur.
  • Süreklilik testi: "Bu aktarım arızi mi, sürekli mi?" sorusunun cevabı sizi 3. basamaktan 2. basamağa taşır. Üretim sistemlerindeki entegrasyonlar neredeyse her zaman süreklidir.

Ayrıntı için Kurum'un yayımladığı Kişisel Verilerin Yurt Dışına Aktarılması Rehberi'ne bakın. Bu yazı hukuki görüş değildir; somut aktarımınız için hukuk danışmanınıza sorun.

Test ortamında gerçek TC kimlik numarası kullanmak: yapmayın

Production DB'nin bir snapshot'ını test/staging ortamına kopyalamak klasik bir anti-pattern. Bu neredeyse kesin bir KVKK ihlalidir çünkü test ortamlarının güvenlik kontrolü (access log, encryption, backup policy) production ile aynı seviyede değildir.

Doğru yaklaşım (Sistem testlerinizde production'dan alınan maskelenmiş veri kullanmak yerine, tc no uret sayfası yardımıyla baştan yeni sentetik kayıtlar üretebilirsiniz):

  1. Synthetic data: algoritma uyumlu ama gerçek olmayan TC kimlik numaraları üretin. TC Üretici aracı tam da bunun için.
  2. Anonymization: production verisini anonimleştirerek test'e taşıyın. Ad/soyad rastgeleleştirilir, TCKN yeniden üretilir, doğum tarihi ay bazında yuvarlanır.
  3. Pseudonymization: TCKN'yi deterministik bir hash ile değiştirin (sha256(tckn + test_salt)). Aynı kullanıcı tüm tabloda aynı pseudo-ID'yi alır; ters çevrilemez.

Ekibinizin test verisi yaşam döngüsünü nasıl kurguladığını test verisi üretiminde en iyi pratikler yazımızda detaylandırdık.

Aydınlatma metni: yazılımcı kontrol listesi

Aydınlatma metnini hukuk yazıyor olabilir, ama yazılım ekibi şunları kontrol etmeli:

  • Toplanan veri kategorileri tam listelenmiş mi? (TCKN, ad, e-posta, IP, device ID, cookie ID)
  • Hukuki sebepler her kategori için belirtilmiş mi?
  • Saklama süreleri her kategori için verilmiş mi ve sizin retention policy'nizle örtüşüyor mu?
  • Veri aktarılan üçüncü taraflar (APM, e-posta servisi, ödeme sağlayıcısı) listelenmiş mi?
  • Yurtdışı aktarımı varsa hukuki dayanağı belirtilmiş mi?

Aydınlatma metni ile kodun örtüşmemesi ("metinde yazmıyor ama biz tutuyoruz") en büyük denetim riskidir. Her yeni field eklediğinizde hukuk ekibine haber verin.

Veri sahibi hakları: teknik uygulama

KVKK madde 11, ilgili kişinin haklarını dokuz bent hâlinde (a–ğ) sayar: işlenip işlenmediğini öğrenme, işlenmişse bilgi talep etme, işlenme amacını ve amaca uygun kullanılıp kullanılmadığını öğrenme, yurt içinde/dışında aktarıldığı üçüncü kişileri bilme, eksik veya yanlış işlenmişse düzeltilmesini isteme, silinmesini/yok edilmesini isteme, bu işlemlerin aktarılan üçüncü kişilere bildirilmesini isteme, münhasıran otomatik sistemlerle analiz edilmesi sonucu aleyhe bir sonuç çıkmasına itiraz etme ve kanuna aykırı işlemeden doğan zararın giderilmesini talep etme.

Bunların teknik tarafı şudur:

  • Erişim hakkı: kullanıcı "benim hakkımda ne tutuyorsunuz" isterse. Self-service bir "verilerimi indir" butonu veya mail üzerinden manuel süreç. Yanıt süresi 30 gün.
  • Düzeltme hakkı: yanlış veri varsa düzeltme. Kullanıcı paneli çoğunlukla çözer.
  • Silme hakkı: "unutulma hakkı". En zoru. Backup'larda ve anonimleştirilmemiş analytics DB'lerinde TCKN varsa bu taleplere nasıl cevap vereceğinizi önceden planlayın.

Silme talebi geldiğinde bir hafta içinde 15 farklı sistemde temizlik yapabileceğinizden emin olun. Aksi halde Kurul'a yapılan şikâyetlerde idari para cezası gündeme gelir. Tutarları bu yazıda vermiyoruz: KVKK idari para cezaları her yıl yeniden değerleme oranıyla güncellenir, dolayısıyla bir yazıda sabitlenen rakam ertesi yıl yanlış olur. Güncel tutarlar için Kurum'un resmî duyurularına bakın.

Toplu işlemler: ekstra dikkat

Toplu TC kimlik doğrulama, validasyon, import/export işlemlerinde KVKK etkisi katlanır. 1 milyon kayıt işleniyorsa:

  • CSV dosyasının S3/object storage'da ne kadar süre durduğu (ideal: işlendikten sonra 24 saat içinde silinsin)
  • Worker loglarında TCKN'lerin görünmemesi
  • Background job payload'larında TCKN'nin encrypted tutulması
  • Job retry queue'sunda ne kadar süre kalacağı (ideal: 3-7 gün)

Bu toplu mimarinin güvenli versiyonunu toplu doğrulama rehberinde anlatıyoruz.

Veri ihlali bildirim süresi

Kişisel veri ihlali (data breach) durumunda KVKK Kurulu'na 72 saat içinde, veri sahiplerine makul süre içinde bildirim yapmanız gerekir. Bunu yapabilmek için:

  • Ekibinizin bir "breach response runbook"u olmalı
  • Hangi tabloda hangi PII olduğunu 5 dakikada cevaplayabilmelisiniz (veri envanteri)
  • İletişim zinciri net olmalı: kim CTO'yu arayacak, kim DPO'yu, kim Kurul formunu dolduracak

Sonuç

KVKK uyumu, hukuk biriminin tek başına çözebileceği bir konu değildir. TC kimlik numarasının her bir noktada (form, DB, log, APM, backup, test ortamı) nerede durduğunu ve ne kadar süre kaldığını bilmek yazılım ekibinin sorumluluğundadır. Yukarıdaki prensipleri sistem tasarımınıza yerleştirirseniz, denetim geldiğinde ekstra iş çıkmaz.

Anonim test verisi için TC Üretici ve Toplu Üretim araçlarını kullanın.