TC Kimlik Numarası Maskeleme: Regex, Doğrulama ve Model ile Tespit

Kısa cevap: TC kimlik numarası maskelemek için önce 11 haneli ve 0 ile başlamayan sayıları regex ile yakalayın, ardından resmî sağlama kuralıyla (10. ve 11. hane kontrolü) doğrulayın. Geçenleri [TCKN] etiketi ya da 123******01 biçimiyle değiştirin. Serbest metinde ad, IBAN ve telefonla birlikte bulmak için bir PII modeli kullanın.

TC kimlik numarası neden maskelenmeli?

TC kimlik numarası (TCKN), bir kişiyi doğrudan tanımlayan kişisel veridir. Destek kayıtlarında, CRM notlarında, uygulama loglarında ve son zamanlarda en sık olarak yapay zekâ asistanlarına yapıştırılan metinlerde karşımıza çıkar. Bir log dosyası ya da bir LLM isteği bu numarayı tutması gerekmeyen bir sisteme taşıdığında, KVKK'daki veri minimizasyonu ilkesiyle çelişen bir durum ortaya çıkar. Maskeleme, veriyi işin gerektirmediği her yerden çıkarmanın en basit yoludur.

Bu rehber geliştiriciler için yazıldı: önce kuralları, sonra kodu, en sonda kuralların yetmediği yeri anlatıyoruz.

TCKN'nin yapısı ve sağlama kuralı

TCKN 11 hanelidir ve ilk hanesi 0 olamaz. Son iki hane, ilk dokuz haneden hesaplanan kontrol haneleridir:

  • 10. hane: (1., 3., 5., 7. ve 9. hanelerin toplamı × 7 − 2., 4., 6. ve 8. hanelerin toplamı) mod 10
  • 11. hane: ilk 10 hanenin toplamı mod 10

Bu kural sayesinde rastgele 11 haneli bir sayının (sipariş numarası, telefon numarasının bir parçası, takip kodu) TCKN sanılma olasılığı büyük ölçüde azalır.

Regex ile ilk filtre

İlk adım aday yakalamaktır. Öncesinde ve sonrasında rakam olmamasını şart koşarak daha uzun sayıların içinden parça koparmayı önleyin:

import re
TCKN_ADAY = re.compile(r"(?<!\d)[1-9]\d{10}(?!\d)")

Bu ifade 11 haneli ve 0 ile başlamayan her sayıyı yakalar. Boşluklu yazımlar ("123 456 789 01") gerçek veride görülür; destekleyecekseniz önce rakamlar arasındaki tekil boşlukları normalleştirin, ama bunun telefon numaralarıyla çakışabileceğini unutmayın.

Sağlama (checksum) ile yanlış pozitifleri azaltmak

def tckn_gecerli(s: str) -> bool:
    if len(s) != 11 or not s.isdigit() or s[0] == "0":
        return False
    d = [int(c) for c in s]
    h10 = ((sum(d[0:9:2]) * 7) - sum(d[1:8:2])) % 10
    h11 = sum(d[:10]) % 10
    return d[9] == h10 and d[10] == h11

def tckn_maskele(metin: str, etiket: str = "[TCKN]") -> str:
    return TCKN_ADAY.sub(
        lambda m: etiket if tckn_gecerli(m.group()) else m.group(), metin
    )

d[0:9:2] 1., 3., 5., 7. ve 9. haneleri; d[1:8:2] 2., 4., 6. ve 8. haneleri seçer. Python'da % operatörü negatif sayılarda da 0–9 arası sonuç verdiği için ek düzeltme gerekmez; başka dillerde (JavaScript, Java) negatif sonucu ((x % 10) + 10) % 10 ile düzeltin.

Test ederken gerçek kişilere ait numara kullanmayın. Sağlama kuralına uyan sentetik numaraları kendi kodunuzla üretin.

Metin içinde bağlam: model ne zaman gerekir?

Regex + sağlama, TCKN gibi yapısı belli veride iyi çalışır. Ama gerçek metinler bundan ibaret değildir:

  • "Ahmet Yılmaz, kimlik no 1234…" cümlesinde ad soyad da kişisel veridir ve regex ile güvenilir biçimde bulunamaz.
  • Adres, doğum tarihi gibi alanlar serbest biçimde yazılır.
  • OCR'dan gelen metinlerde rakamlar arasına harf veya boşluk karışabilir.

Bu durumlar için bağlamı okuyabilen, Türkçe metinle eğitilmiş bir model gerekir. Türkçe PII tespit modelimiz metni ve neyin maskeleneceğini söyleyen kısa bir talimatı alır; ad, TCKN, IBAN, telefon ve e-posta gibi verileri etiketlerle değiştirilmiş metni geri döndürür. Konum (offset) döndüren bir NER modeli değildir; çıktısı maskelenmiş metindir. En sağlam yaklaşım katmanlıdır: yapısal veriler için kural + sağlama, bağlama bağlı veriler için model. İki katman birbirinin açığını kapatır.

Kod yazmadan denemek isterseniz maskeleme aracını kullanabilirsiniz.

Maskeleme biçimleri: tam, kısmi, etiket

Hangi biçimi seçeceğiniz, maskelenmiş metni kimin ne için kullanacağına bağlıdır:

BiçimÖrnekNe zaman?
Etiket[TCKN]LLM istekleri, analiz; numaranın kendisi gerekmiyorsa
Numaralı etiket[TCKN_1]Aynı metinde birden fazla kişi varsa, cevabı geri eşlemek için
Kısmi123******01Çağrı merkezi ekranları; kullanıcının numarayı tanıması gerekiyorsa
Hash/tokentk_8f2a…Kayıtları birleştirmek gerekiyorsa (tuzlu hash, anahtar ayrı saklanır)

LLM'e gönderirken numaralı etiket en kullanışlısıdır: modelin cevabındaki [TCKN_1] ifadesini, eşleme tablosu yalnızca sizin sisteminizde kalacak şekilde gerçek değere geri çevirebilirsiniz. Numaralandırmayı ve eşleme tablosunu kural katmanınız üretir; PII modeli numarasız etiket ([TCKN] gibi) yazar.

Sık yapılan hatalar

  1. Yalnızca 11 hane kontrolü: Sağlama yapmazsanız sipariş ve takip numaraları da maskelenir; metin anlamsızlaşır.
  2. Maskelemeyi loglamadan sonra yapmak: Ham metin bir kez log'a yazıldıysa sorun zaten oluşmuştur. Maskeleme, isteğin sisteme girdiği ilk noktada çalışmalı.
  3. Eşleme tablosunu metinle birlikte saklamak: Geri çevrilebilir maskelemenin anahtarı, maskelenmiş veriyle aynı yerde durmamalı.
  4. Sadece TCKN'ye odaklanmak: Aynı metinde IBAN, telefon, e-posta ve ad da çoğunlukla bulunur. Hangi verilerin maskelenmesi gerektiğini Kişisel veri ve yapay zekâ rehberinde anlattık.
  5. Test verisi olarak gerçek numara kullanmak: Sentetik ama sağlamadan geçen numaralar üretin.

Hukuk ve uyum ekipleri için hazırladığımız başlangıç seti: Hukuk ve uyum kiti.

SSS

TCKN maskelemek KVKK'ya uyum için yeterli mi?

Hayır. Maskeleme önemli bir teknik tedbirdir ama tek başına uyum sağlamaz; işleme amacı, hukuki dayanak ve saklama süresi gibi konular ayrıca ele alınmalıdır. Metinlerin hangi kişisel veri kategorilerini içerdiğini görmek için KVKK sınıflandırıcısına bakabilirsiniz. Bu rehber hukuki görüş değildir.

Regex mi, model mi?

İkisi birlikte. TCKN için regex + sağlama hızlı ve açıklanabilirdir; ad soyad ve adres gibi bağlama bağlı veriler için model gerekir.

Yabancı uyruklu kimlik numaraları da yakalanır mı?

Yabancılara verilen kimlik numaraları da 11 hanelidir ve 99 ile başlar; aynı sağlama kuralı genellikle bunlar için de kullanılır. Kendi verinizle test edin.

Maskelemeyi tarayıcıda yapabilir miyim?

Evet, kural katmanı JavaScript'e kolayca taşınır. Model katmanı için yerel çalışan bir sürüm ya da sunucu tarafı daha uygundur.