Bir geliştiricinin dizüstü bilgisayarındaki test veritabanı dökümü, bir analistin raporlama için aldığı CSV çıktısı, bir destek ekibinin sorun ayıklamak için kopyaladığı tablo — hepsi aynı kaynağa dayanır ve hepsinde gerçek müşterilerin adı, telefonu, adresi ve kimlik bilgisi bulunur. Veritabanı anonimleştirme, bu kopyaların kişisel veri taşımadan da işe yarar hâle getirilmesiyle ilgilidir ve 6698 sayılı KVKK kapsamında yalnızca iyi bir alışkanlık değil, çoğu senaryoda beklenen bir teknik tedbirdir.
Bu rehberde anonimleştirme, maskeleme ve takma adlaştırma kavramlarının neden aynı şey olmadığını netleştireceğiz — bu ayrım, hukuki sonucu doğrudan değiştirdiği için en kritik bölüm. Ardından veri envanterini çıkarmayı, tekniklerin SQL karşılıklarını, yeniden kimliklendirme riskini ve k-anonimlik kontrolünü, üretimden maskeli bir test kopyası üretme sürecini ve saklama süresi ile periyodik imha disiplinini ele alacağım. Not: burada anlatılanlar teknik uygulama örnekleridir, hukuki danışmanlık yerine geçmez; kritik kararlarda kendi hukuk danışmanınıza başvurun.
Anonimleştirme, Maskeleme ve Takma Adlaştırma Aynı Şey Değil#
Bu üç kavram günlük konuşmada birbirinin yerine kullanılıyor ama sonuçları tamamen farklı.
Anonimleştirme, verinin kimliği belirli veya belirlenebilir bir gerçek kişiyle hiçbir şekilde ilişkilendirilemeyecek hâle getirilmesidir. Bu işlem geri döndürülemez olmalıdır. Gerçekten anonim hâle gelmiş bir veri artık kişisel veri sayılmaz ve KVKK kapsamı dışına çıkar. Uygulamada bu, göründüğü kadar kolay değildir — birazdan göreceğimiz yeniden kimliklendirme riski tam da bu yüzden vardır.
Takma adlaştırma (pseudonymization), kimlik bilgisinin bir takma değerle değiştirilmesidir; ancak eşleştirme tablosu ya da anahtar saklandığı için işlem geri döndürülebilir. Bu yüzden takma adlaştırılmış veri hâlâ kişisel veridir ve KVKK yükümlülükleri devam eder. Yararlıdır — ihlal hâlinde etkiyi azaltır — ama "artık kişisel veri değil" demenizi sağlamaz.
Maskeleme, verinin bir kısmının gizlenmesidir (05** *** 12 34 gibi). Amacı ekranda ya da logda gereksiz ifşayı önlemektir; kaynak veri hâlâ tam hâliyle durur.
| Yöntem | Geri döndürülebilir mi | Sonuç kişisel veri mi | Tipik kullanım |
|---|---|---|---|
| Anonimleştirme | Hayır | Hayır | İstatistik, uzun dönem analiz |
| Takma adlaştırma | Evet (anahtarla) | Evet | İç analiz, olay inceleme |
| Maskeleme | Kaynak durur | Evet | Ekran, log, destek arayüzü |
| Şifreleme | Evet (anahtarla) | Evet | Saklama güvenliği |
Şifrelemenin de bu tabloda olması tesadüf değil: şifreleme veriyi korur ama kişisel veri olmaktan çıkarmaz. İkisi birbirini tamamlar; ayrıntısı için veritabanında şifreleme yazısına bakabilirsiniz.
Önce Veri Envanteri: Hangi Kolon Kişisel Veri#
Anonimleştirmeye teknikle değil envanterle başlanır. Hangi tablonun hangi kolonunda ne tür kişisel veri bulunduğunu bilmeden, hangisini nasıl işleyeceğinize karar veremezsiniz. Çoğu ekip bu adımı atlar ve musteriler tablosunu maskeledikten sonra destek_talepleri.mesaj alanında telefon numaralarının serbest metin olarak durduğunu fark eder.
Envanteri çıkarmak için şema üzerinden bir tarama iyi bir başlangıçtır:
-- PostgreSQL: adı şüpheli olan kolonları listele
SELECT table_schema, table_name, column_name, data_type
FROM information_schema.columns
WHERE table_schema NOT IN ('pg_catalog','information_schema')
AND (column_name ~* '(ad|soyad|isim|eposta|email|mail|telefon|gsm|adres|tckn|kimlik|dogum|iban|kart)')
ORDER BY table_name, column_name;
-- MySQL: aynı tarama
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'uygulama'
AND (COLUMN_NAME REGEXP 'ad|soyad|eposta|email|telefon|adres|tckn|kimlik|dogum|iban');
Bu tarama başlangıçtır, bitiş değildir. İki kaynağı elle incelemeniz şart: serbest metin alanları (destek mesajları, notlar, açıklamalar) ve JSON kolonları. Buralarda kişisel veri şema taramasıyla bulunamaz.
Her kolonu üç kategoriye ayırın: doğrudan tanımlayıcı (ad soyad, kimlik numarası, e-posta, telefon), dolaylı tanımlayıcı (doğum tarihi, posta kodu, cinsiyet, işyeri — tek başına değil ama birleşince kimliklendirir), hassas veri (sağlık, biyometrik, din, sendika üyeliği — KVKK'da özel nitelikli kişisel veri kategorisi). Kategoriye göre uygulanacak teknik değişir.
Anonimleştirme Teknikleri ve SQL Karşılıkları#
Silme (suppression) en basitidir: kolonu tamamen boşaltırsınız. Analize gerçekten gerek yoksa en güvenli yöntemdir.
Değiştirme (substitution), gerçek değerin sahte ama gerçekçi bir değerle değiştirilmesidir. Test ortamlarında en çok tercih edilen yöntemdir çünkü veri hâlâ kullanılabilir görünür.
Genelleştirme (generalization), hassasiyeti düşürmektir: tam doğum tarihi yerine doğum yılı, tam adres yerine il, tam maaş yerine aralık.
Karıştırma (shuffling), bir kolondaki değerleri satırlar arasında rastgele yeniden dağıtmaktır. Dağılım korunur, birey–değer eşleşmesi bozulur.
Gürültü ekleme (noise addition), sayısal değerlere küçük rastgele sapmalar eklemektir; toplamlar ve ortalamalar kabaca korunur.
-- 1) Doğrudan tanımlayıcıları değiştir (sıralı, tekrarlanabilir sahte değerler)
UPDATE musteriler
SET ad = 'Ad' || id,
soyad = 'Soyad' || id,
eposta = 'kullanici' || id || '@ornek.com',
telefon = '0555' || lpad((id % 10000000)::text, 7, '0');
-- 2) Genelleştirme: tam doğum tarihi yerine yılın ilk günü
UPDATE musteriler
SET dogum_tarihi = date_trunc('year', dogum_tarihi)::date;
-- 3) Posta kodunu ilk üç haneye indir (bölge kalsın, mahalle kalmasın)
UPDATE musteriler
SET posta_kodu = left(posta_kodu, 3) || '00';
-- 4) Serbest metin alanını tamamen temizle: içinde ne olduğunu bilemezsiniz
UPDATE destek_talepleri SET mesaj = 'Anonimleştirilmiş içerik';
Karıştırma için PostgreSQL'de kısa bir yöntem:
-- Şehir kolonundaki değerleri satırlar arasında rastgele yeniden dağıt
WITH karisik AS (
SELECT id,
sehir,
row_number() OVER (ORDER BY random()) AS yeni_sira,
row_number() OVER (ORDER BY id) AS eski_sira
FROM musteriler
)
UPDATE musteriler m
SET sehir = k2.sehir
FROM karisik k1
JOIN karisik k2 ON k1.yeni_sira = k2.eski_sira
WHERE m.id = k1.id;
Takma adlaştırma gerekiyorsa (örneğin aynı müşterinin farklı tablolardaki kayıtlarını birbirine bağlamaya devam etmeniz gerekiyorsa), gizli anahtarlı bir HMAC kullanın. Düz md5(tckn) gibi bir özet yeterli değildir: kimlik numarası kısa ve kurallı bir yapıya sahip olduğu için tüm olasılıkları deneyerek geri çözülebilir.
-- Anahtarlı takma ad: aynı kişi her tabloda aynı takma adı alır,
-- ancak anahtar bilinmeden geri çözülemez
CREATE EXTENSION IF NOT EXISTS pgcrypto;
UPDATE musteriler
SET takma_ad = encode(hmac(tckn, :'takma_ad_anahtari', 'sha256'), 'hex');
-- Takma ad üretildikten sonra kaynak kolonu kaldırın
ALTER TABLE musteriler DROP COLUMN tckn;
Anahtarı saklamaya devam ettiğiniz sürece bunun anonimleştirme olmadığını, takma adlaştırma olduğunu unutmayın. Gerçekten anonim bir çıktı istiyorsanız anahtarı işlem sonunda imha etmeniz gerekir.
Yeniden Kimliklendirme Riski ve k-Anonimlik#
Anonimleştirmenin en sık yapılan hatası, yalnızca doğrudan tanımlayıcıları silip işi bitmiş saymaktır. Ad ve e-posta silinmiş bir tabloda hâlâ doğum tarihi, posta kodu ve cinsiyet duruyorsa, bu üçlü çoğu popülasyonda tek bir kişiye kadar daraltabilir. Buna yeniden kimliklendirme (re-identification) denir ve gerçek bir risktir.
Ölçmek için kullanılan basit ve etkili ölçüt k-anonimliktir: veri setindeki her kayıt, aynı dolaylı tanımlayıcı kombinasyonunu paylaşan en az k-1 başka kayıtla birlikte bulunmalıdır. Yani k = 5 ise, hiçbir kombinasyon 5'ten az kişiyi işaret etmemelidir.
-- Hangi dolaylı tanımlayıcı kombinasyonları tekil kişiye iniyor
SELECT dogum_yili, posta_kodu, cinsiyet, count(*) AS kisi_sayisi
FROM anonim_musteriler
GROUP BY dogum_yili, posta_kodu, cinsiyet
HAVING count(*) < 5 -- k = 5 eşiği
ORDER BY kisi_sayisi;
Bu sorgu satır döndürüyorsa anonimleştirmeniz eksiktir. Çözüm, genelleştirmeyi bir kademe artırmaktır: doğum yılını on yıllık aralığa çevirin, posta kodunu ile indirin ya da riskli satırları tamamen çıkarın.
| Genelleştirme kademesi | Doğum tarihi | Posta kodu | Kimliklendirme riski |
|---|---|---|---|
| Ham | 1987-03-14 | 34394 | Çok yüksek |
| Orta | 1987 | 343** | Orta |
| Yüksek | 1980-1989 | İstanbul | Düşük |
| Toplulaştırılmış | Yaş grubu | Bölge | Çok düşük |
Buradaki ödünleşme açıktır: veri ne kadar anonim olursa o kadar az işe yarar. Doğru denge, verinin hangi amaçla kullanılacağına bakarak kurulur. Aylık satış raporu için yaş grubu yeterlidir; bireysel davranış analizi içinse zaten anonim veri kullanamazsınız ve aydınlatma metni ile açık rıza gibi hukuki dayanaklara ihtiyaç duyarsınız.
Üretimden Maskeli Test Kopyası Üretmek#
Pratikte en çok ihtiyaç duyulan iş budur: üretim verisinin yapısını koruyan ama kişisel veri taşımayan bir test kopyası. Süreci güvenli kurmanın anahtarı, maskelemenin ara bir ortamda yapılması ve ham kopyanın hiçbir zaman geliştirici ortamına ulaşmamasıdır.
- Üretimden yedeği alın ve erişimi kısıtlı bir ara sunucuya geri yükleyin.
- Ara sunucuda maskeleme betiğini çalıştırın; betik depoda sürümlü ve gözden geçirilmiş olmalı.
- Maskelemenin başarılı olduğunu doğrulayan kontrol sorgularını çalıştırın.
- Maskelenmiş veritabanından yeni bir döküm alın.
- Ara sunucudaki ham veriyi ve ilk dökümü güvenli biçimde imha edin.
- Yalnızca maskelenmiş dökümü test ortamına dağıtın.
#!/usr/bin/env bash
# maskele.sh — ara sunucuda çalışır, üretimde ASLA çalıştırılmaz
set -euo pipefail
if [ "${ORTAM:-}" = "production" ]; then
echo "HATA: bu betik üretimde çalıştırılamaz." >&2
exit 1
fi
psql -v ON_ERROR_STOP=1 -d test_kopya -f maskeleme.sql
psql -v ON_ERROR_STOP=1 -d test_kopya -f dogrulama.sql # kontrol sorguları
pg_dump -Fc test_kopya > /cikti/test-maskeli-$(date +%F).dump
Doğrulama adımını atlamayın; maskeleme betiğinin bir tabloyu unutmuş olması en sık karşılaşılan durumdur. Kontrol sorguları, kalan kişisel veri izlerini yakalamalıdır:
-- Maskeleme sonrası kalan gerçek e-posta var mı (ornek.com dışında hiçbir adres kalmamalı)
SELECT count(*) AS maskelenmemis_eposta
FROM musteriler
WHERE eposta NOT LIKE '%@ornek.com';
-- Serbest metinde telefon deseni kalmış mı
SELECT count(*) AS supheli_metin
FROM destek_talepleri
WHERE mesaj ~ '0[0-9]{10}';
Bu sorgular sıfırdan farklı bir sayı döndürüyorsa döküm alınmamalıdır. Betiği, doğrulama başarısız olduğunda çıktı üretmeyecek biçimde yazın — insan disiplinine değil, otomasyona güvenin. Test verisinin tamamen sentetik üretilmesi çoğu durumda daha güvenli bir alternatiftir; yöntemler için test verisi üretme ve seed stratejileri yazısına bakın.
Saklama Süresi ve Periyodik İmha#
KVKK'nın en çok göz ardı edilen tarafı, veriyi ne kadar süre saklayacağınıza dair yükümlülüktür. Kişisel veri, işlenme amacı ortadan kalktığında silinmeli, yok edilmeli ya da anonim hâle getirilmelidir. Uygulamada bu, her veri kategorisi için bir saklama süresi belirlemenizi ve bu sürenin sonunda otomatik bir işlem çalıştırmanızı gerektirir.
Silmek yerine anonimleştirmek çoğu zaman daha akıllıcadır: geçmiş satış istatistiklerinizi kaybetmeden kişisel bağı koparırsınız.
-- Saklama süresi dolan kayıtları silmek yerine anonimleştir
UPDATE musteriler
SET ad = 'Anonim', soyad = 'Kullanıcı',
eposta = 'silinmis-' || id || '@ornek.com',
telefon = NULL, adres = NULL, tckn = NULL,
anonimlestirildi_mi = true
WHERE son_islem_tarihi < now() - interval '10 years'
AND anonimlestirildi_mi = false;
Log ve olay tabloları gibi büyük ve zaman bazlı veriler için bölümlendirme (partitioning) çok daha verimlidir; koca bir DELETE çalıştırmak yerine bölümü düşürürsünüz:
-- Zaman bazlı bölüm düşürmek, milyonlarca satırı silmekten kat kat hızlıdır
DROP TABLE erisim_loglari_2024_01;
Bu işlemleri düzenli bir görev olarak zamanlayın ve çalıştığını kaydedin — periyodik imha faaliyetinin kayıt altına alınması, denetim anında gösterebileceğiniz en somut kanıttır.
# Aylık anonimleştirme görevi ve çıktının log'a yazılması
0 3 1 * * /usr/local/bin/anonimlestir.sh >> /var/log/kvkk-imha.log 2>&1
⚠️ Bir noktayı özellikle belirtmek gerekir: veriyi canlı veritabanından anonimleştirdiğinizde yedeklerde hâlâ ham hâli durur. Bu yüzden yedek saklama sürenizin de bir sınırı olmalı ve eski yedekler döngüsel olarak imha edilmelidir. Yedek döngüsünü kurgularken 3-2-1 yedekleme stratejisi yazısındaki saklama planı bölümü doğrudan bu ihtiyaca cevap verir.
Sık Yapılan Hatalar#
Yalnızca doğrudan tanımlayıcıları silmek en yaygın hatadır. Ad ve e-posta gittiğinde iş bitmez; doğum tarihi, posta kodu, cinsiyet üçlüsü çoğu veri setinde bireyi tekilleştirir. k-anonimlik kontrolünü mutlaka çalıştırın.
Düz özet (hash) kullanmak ikinci hatadır. md5 ya da sha256 ile özetlenmiş bir kimlik numarası, olası tüm numaraların özeti hesaplanarak dakikalar içinde geri çözülebilir. Gizli anahtarlı HMAC kullanın ve gerçek anonimlik istiyorsanız anahtarı imha edin.
Serbest metin alanlarını atlamak üçüncüsüdür. Destek mesajları, sipariş notları ve iç yorumlar; müşteri adı, telefon ve bazen kimlik numarası içerir. Bu alanları maskelemeye çalışmak yerine tamamen değiştirmek çok daha güvenlidir.
Maskeleme betiğini üretimde çalıştırmak dördüncüsüdür ve geri dönüşü yoktur. Betiğin başına ortam kontrolü koyun; production ortamında çalışmayı reddetsin. Bu üç satırlık kontrolün bir gün gerçekten hayat kurtardığı çok sayıda hikâye var.
İhlal bildirimini planlamamak beşincisidir. Bir veri ihlali yaşandığında KVKK, gecikmeksizin Kurul'a bildirim yapılmasını bekler. Bunu ihlal gününde öğrenmek yerine, kimin bildirim yapacağını ve hangi bilgilerin toplanacağını önceden yazılı hâle getirin.
Sıkça Sorulan Sorular#
Anonimleştirilmiş veri KVKK kapsamında mı#
Gerçekten anonim hâle getirilmiş veri, kimliği belirli veya belirlenebilir bir gerçek kişiyle ilişkilendirilemediği için kişisel veri sayılmaz ve KVKK yükümlülükleri o veri için sona erer. Ancak buradaki eşik yüksektir: işlem geri döndürülemez olmalı ve mevcut başka verilerle birleştirildiğinde de kimliklendirmeye izin vermemelidir. Eşleştirme tablosunu ya da anahtarı saklamaya devam ediyorsanız yaptığınız şey anonimleştirme değil takma adlaştırmadır ve veri hâlâ kişisel veridir.
Maskeleme ile anonimleştirme arasındaki fark nedir#
Maskeleme, verinin bir kısmını görüntülemede gizlemektir; kaynak veri tam hâliyle veritabanında durmaya devam eder ve yetkili biri onu görebilir. Anonimleştirme ise kaynağın kendisini geri döndürülemez biçimde değiştirir; orijinal değer artık hiçbir yerde yoktur. Destek ekranında telefonun son dört hanesini göstermek maskelemedir; test kopyasındaki tüm telefonları sahte numaralarla değiştirip ham kopyayı imha etmek anonimleştirmedir.
Test ortamında gerçek müşteri verisi kullanabilir miyim#
Kişisel veri içeriyorsa kullanmamalısınız. Test ortamları genellikle üretimden daha az korunur, daha çok kişiye açıktır ve dökümleri kolayca kopyalanır; bu da ihlal riskini belirgin biçimde artırır. Doğru yaklaşım ya tamamen sentetik veri üretmek ya da erişimi kısıtlı bir ara ortamda maskeleme yapıp yalnızca maskelenmiş kopyayı dağıtmaktır. Ham üretim dökümünün geliştirici makinelerine inmesi her durumda engellenmelidir.
Verinin gerçekten anonim olduğunu nasıl kontrol ederim#
En pratik teknik kontrol k-anonimlik testidir: dolaylı tanımlayıcı kombinasyonlarını gruplayıp her grubun kaç kişi içerdiğini sayarsınız. Belirlediğiniz eşiğin altında kalan gruplar varsa, o kombinasyonlar bireyi tekilleştirebiliyor demektir ve genelleştirmeyi artırmanız gerekir. Buna ek olarak serbest metin alanlarında düzenli ifadelerle telefon, e-posta ve kimlik numarası deseni araması yapın; şema taraması bu alanlardaki veriyi asla göstermez.
Kişisel veriyi ne kadar süre saklayabilirim#
Kanun tek bir süre belirtmez; veriyi işleme amacınız ortadan kalktığında saklamayı bırakmanız gerekir. Pratikte her veri kategorisi için ayrı bir saklama süresi belirlenir ve bu süreler bir saklama ve imha politikasında yazılı hâle getirilir. Süreleri belirlerken ilgili mevzuatın öngördüğü zorunlu saklama yükümlülüklerini (örneğin ticari ve mali kayıtlar için) göz önünde bulundurmanız gerekir. Süre dolduğunda silme, yok etme ya da anonim hâle getirme işlemlerinden birini uygulayıp bu işlemi kayıt altına alın.
Yedeklerdeki kişisel veriyi nasıl yönetirim#
Canlı veritabanından bir kaydı sildiğinizde ya da anonimleştirdiğinizde, o kayıt eski yedeklerde ham hâliyle durmaya devam eder. Yedekleri tek tek düzenlemek pratik değildir; bunun yerine yedekler için de bir saklama süresi belirleyip süresi dolanları imha etmek kabul edilen yaklaşımdır. Silme talebi alan bir kişinin verisi, yedek döngüsü tamamlandığında ortadan kalkar. Bu süreci hem yazılı politikanızda belirtin hem de yedeklerin şifreli saklanmasını sağlayarak ara dönemdeki riski azaltın.
Kapanış#
Anonimleştirme, bir kez yapılıp unutulan bir işlem değil; veri envanterinden imha planına uzanan sürekli bir disiplindir. Aklınızda kalması gereken dört alışkanlık şunlar: işe teknikle değil envanterle başlayın ve serbest metin ile JSON alanlarını mutlaka elle inceleyin; doğrudan tanımlayıcıları silmenin yetmediğini bilin ve k-anonimlik kontrolünü rutin hâline getirin; maskelemeyi erişimi kısıtlı bir ara ortamda yapıp doğrulama sorguları geçmeden çıktı üretmeyin; saklama sürelerini yazılı hâle getirip periyodik imhayı zamanlanmış ve kayıtlı bir göreve dönüştürün.
Bu sürecin çalışabilmesi için üretim, ara ve test ortamlarının birbirinden gerçekten ayrı olması gerekir; ayrı bir VDS ya da bulut sunucu örneği, maskeleme adımını üretimden izole etmenin en temiz yoludur. Verinin diskte ve yedekte korunması için yedekleme hizmetimize ve aktarım güvenliği için SSL sertifikası seçeneklerine bakabilir, sunucu sertleştirme ile erişim kontrolünü devretmek isterseniz sunucu yönetimi hizmetimizden yararlanabilirsiniz.