Exploring Infinite Possibilities on FrontEnd 🚀
Burak Sağlık
Search...

Wed Oct 07 2026

Veri Şifreleme ve Arama: Blind Indexing, Deterministik Şifreleme Rehberi

Veri Şifreleme ve Arama: Blind Indexing, Deterministik Şifreleme Rehberi

🎯 Veri Güvenliği ile Arama Özelliğini Bir Arada Korumak

Hazırsan başlayalım 🚀

Bir veri hattında hassas kişisel veriler (PII) — TC kimlik numarası, e‑posta, telefon — saklıyorsunuz.
Güvenlik gereği bu verileri şifrelemek istiyorsunuz, ama aynı zamanda:

  • Kullanıcı arama yapabilmeli (ör. “ Ahmet ” yazıp ilgili kayıtları bulmalı)
  • Raporlama ve filtreleme SQL LIKE / ILIKE gibi sorgularla çalışmalı

Basit bir tek yönlü şifreleme (AES‑GCM, RSA vb.) uygularsanız veriler karışık bir blob haline gelir.
Sonuç? Arama imkansız hale gelir ❌

Neden basit şifreleme yetmez?

  • Deterministik değil → Aynı veri her seferinde farklı ciphertext üretir.
  • Indexlenemez → Veritabanı indeksleri plaintext’e dayanır, şifreli veride çalışmaz.
  • Performans → Her sorguda tüm satırları çözmek (decrypt) maliyetli ve pratik değil.

Arama yeteneğini nasıl koruyoruz? 🔎

  1. Deterministik / Format‑Preserving Encryption (FPE)

    • Aynı plaintext → her zaman aynı ciphertext.
    • İndekslenebilir, WHERE email = ? gibi sorgular çalışır.
  2. Searchable Encryption / Blind Index

    • Hassas alanın hash’ini (HMAC‑SHA256 + secret key) ayrı bir kolon olarak saklarsınız.
    • Arama sırasında kullanıcı girdisini aynı hash fonksiyonundan geçirirsiniz → indeksli karşılaştırma.
  3. Tokenization

    • Gerçek veriyi token ile değiştirir, token’ları ayrı bir güvenli vault’ta tutarsınız.
    • Arama token üzerinden yapılır, asla plaintext’e erişmezsiniz.
  4. Hybrid Yaklaşım

    • Çok sık aranan alanlarda deterministik şifreleme / blind index.
    • Nadiren sorgulanan, yüksek hassasiyetli alanlarda güçlü rastgele şifreleme.

Kısa özet ✅

Yöntem Avantaj Dezavantaj
Deterministik / FPE İndekslenebilir, hızlı arama Aynı verinin tekrarı görünür (pattern leakage)
Blind Index (HMAC) Güvenli, indeksli, pattern leakage azalır Ekstra kolon + key yönetimi
Tokenization Veri asla veritabanında yok Vault erişimi gerekir, ekstra latans
Hybrid Güvenlik‑performans dengesi Tasarım karmaşıklığı artar

Bu bölümde sorunu tanıdık, basit şifrelemenin aramayı nasıl kırdığını gördük ve arama yeteneğini koruyan ana stratejileri özetledik.

Sonraki kısımda bu yöntemlerden birini (ör. Blind Index) adım adım kodlayarak nasıl entegre edeceğimizi görelim 🛠️


❗️ Basit Şifrelemenin Riskleri ve Kayıplar

Hazırsan bu konuyu da beraber çözelim. Basit şifreleme (örneğin AES ile bir alanı tek başına şifrelemek) ilk bakışta "güvenli" görünse de, gerçek hayatta ciddi kayıplar getiriyor. 🎯

Neden arama özelliği kayboluyor? 🔍

Veritabanında bir kolonu şifrelediğinizde, o veri artık anlamsız bir bayt dizisi haline gelir.

  • SELECT * FROM users WHERE email = 'ahmet@ornek.com' sorgusu artık sonuç vermez ⛔
  • LIKE '%@ornek.com' gibi kısmi aramalar da işe yaramaz
  • İndeksler (index) şifrelenmiş veride anlamsız hale gelir

Ne oluyor burada?
Veriyi okumak için her satırı çekip, uygulama katmanında şifresini çözmeniz (decrypt) gerekiyor. Bu da:

  • Performans kabusu 🐢
  • Bellek/CPU yükü 📈
  • Ölçeklenebilirlik sorunu 📉

KVKK ve GDPR uyumu nasıl etkileniyor? ⚖️

Her iki yönetmelik de "veri sahibinin hakları" konusunda net: erişim, düzeltme, silme hakları vardır.

Senaryo Basit şifrelemeyle durum
Kullanıcı "verilerimi göster" derse Tüm tablo çekilip decrypt edilmek zorunda 😰
"E-postamı sil" derse Arama yapılamadığı için hepsini tarayıp bulman gerekir
Denetim (audit) gelirse "Bu veriyi nasıl buldunuz?" sorusuna cevap vermek zordur 📋

Özetle: Basit şifreleme, veriyi korur ama yönetilemez hale getirir. 🛠

Güvenlik ve kullanılabilirlik dengesinde kayıplar ⚖️

Kazanç Kayıp
Veri sızıntısında okunamazlık ✅ Arama, filtreleme, raporlama yok ❌
Basit uygulama ✅ Uygulama katmanı karmaşıklığı artar (her yerde decrypt) ❌
— İndeks kullanılamaz, full table scan kaçınılmaz ❌
— Yedek/arşiv okunamaz hale gelebilir ❌

Pratik bir örnek: E-posta adresi şifrelendiğinde 📧

Diyelim ki users tablosunda email kolonunu AES-256 ile şifrelediniz.

-- Veritabanında şu duruyor:
id | email_encrypted
---|----------------
1  | 0xA3F2... (binary blob)
2  | 0x7B9C...

Artık şunları YAPAMAZSINIZ:

  • WHERE email = 'ayse@sirket.com' → Sonuç yok ⛔
  • WHERE email LIKE '%@sirket.com' → Çalışmaz ⛔
  • ORDER BY email → Anlamsız sıralama ⛔
  • UNIQUE constraint → Veritabanı düzeyinde zorlanamaz ⛔

Ne yapmalıyız?
Bu durumda şifreli arama (searchable encryption), deterministik şifreleme (deterministic encryption) veya tokenizasyon gibi yöntemlere ihtiyacımız var. Ama onlar da kendi getirdikleri risklerle beraber... 😉


Kısa özet: Basit şifreleme "veriyi gizler" ama "veriyi kullanamaz" hale getirir. KVKK/GDPR süreçlerinde kanıtlanabilir erişim ve hızlı yanıt gerektiğinde bu yöntem sizi zor durumda bırakır. ❗️


🔁 Arama Olaraklı Şifreleme Yaklaşımları

Veritabanında şifreli veriler üzerinde arama yapmak, klasik "encrypt-then-store" mantığıyla çelişiyor. Çünkü şifreleme veriyi karıştırır, sıralama ve eşleştirme imkansız hale getirir. Peki ya kullanıcı "email = 'ayse@example.com'" diye arama yapmak istiyorsa? 🤔

İşte bu noktada devreye arama destekli şifreleme (searchable encryption) yaklaşımları giriyor. Hangi yöntemi ne zaman kullanacağını bilmek, hem güvenlik hem de performans açısından kritik. Hadi üç ana tekniği tek tek inceleyelim 👇


🎯 1. Blind Indexing (Kör İndeksleme) — "İndeksi şifrele, veriyi şifrele"

Mantık: Asıl veriyi (ör. e-posta) güçlü bir şifrelemeyle (AES-GCM) saklarsın. Arama için ayrı bir deterministik "blind index" oluşturursun — bu indeks, verinin kendisinden değil, bir keyed hash'ten (HMAC veya Argon2id) türetilir.

Kullanıcı Verisi → Şifrele (AES-GCM) → Depola
Kullanıcı Verisi → HMAC(secret_key, veri) → Blind Index → İndeksle (B-tree / Hash Index)
Arama Sorgusu   → HMAC(secret_key, sorgu) → Index Lookup → Eşleşen Satırları Getir → Şifreleri Çöz

Nasıl çalışıyor?

  • HMAC(secret, "ayse@example.com") her zaman aynı çıktüyü verir → eşitlik sorgusu (WHERE blind_idx = ?) çalışır.
  • Asıl veri asla indekslenmez, sadece şifreli hali depolanır.
  • secret_key sadece uygulama sunucusunda रहता; veritabanı sızsa bile indeks tersine çevrilemez (rainbow table koruması için per-user salt veya pepper eklenebilir).

Ne zaman uygun?

  • ✅ Eşitsiz arama (equality search) yeterliyse: "bu e-posta kime ait?"
  • ✅ Yüksek performans, düşük gecikme gerekiyorsa (standart DB indeksi kullanırsın).
  • ✅ Sıralama (ORDER BY), aralık sorgusu (BETWEEN), LIKE gerekmiyorsa.

Dikkat ⚠️

  • Sadece eşitlik sorgusu destekler.
  • Aynı veri her zaman aynı blind index üretir → frekans analizi riski var (hangı e-posta en çok tekrar ediyor?). Mitigasyon: per-row salt + uygulama tarafında normalizasyon.

🔁 2. Deterministic Encryption (Deterministik Şifreleme) — "Aynı girdi, aynı çıktı"

Mantık: Aynı plaintext her zaman aynı ciphertext'i üreten bir şifreleme modu (ör. AES-SIV, AES-GCM-SIV veya AES-ECB asla kullanma!). Böylece veritabanı indeksi doğrudan ciphertext üzerinde kurulabilir.

# Basit bir gösterim (production'da AES-GCM-SIV veya libsodium crypto_aead_det_xchacha20poly1305 kullan)
from cryptography.hazmat.primitives.ciphers.aead import AESGCMSIV

key = b"32-bytes-very-secret-key-123456"  # 32 byte
aad = b"user-email-column"                 # Associated Authenticated Data

def encrypt_deterministic(plaintext: bytes) -> bytes:
    # AES-GCM-SIV: deterministic, nonce-reuse resistant
    return AESGCMSIV(key).encrypt(b"", plaintext, aad)  # nonce boş → deterministik

def decrypt_deterministic(ciphertext: bytes) -> bytes:
    return AESGCMSIV(key).decrypt(b"", ciphertext, aad)

Ne zaman uygun?

  • ✅ Blind indexing kadar ekstra depolama/işlem istemez (tek sütun).
  • ✅ Eşitsiz arama + JOIN işlemleri gerekiyorsa (foreign key olarak ciphertext kullanılabilir).
  • ✅ Uygulama katmanında ek HMAC hesaplaması yapmak istemiyorsan.

Dikkat ⚠️

  • Frekans analizi riski blind indexing'den daha yüksek — ciphertext doğrudan görülebilir.
  • Sıralama, aralık, LIKE yok.
  • Anahtar rotasyonu zordur (tüm veriyi yeniden şifrelemek gerekir).

🧠 3. Homomorphic Encryption / FHE (Tam Homomorfik Şifreleme) — "Şifreli veride hesap yap"

Mantık: Veriyi şifreli halde bırakıp, arama/filtreleme mantığını da şifreli alanda çalıştıran matematiksel şema. En güçlü (ve en yavaş) yöntem.

Kullanıcı Verisi → FHE.Encrypt(pk) → Ciphertext (ör. CKKS / TFHE-2 şeması)
Arama Sorgusu    → FHE.Encrypt(pk) → Encrypted Query
Sunucu           → FHE.Eval(circuit, ciphertext, query) → Encrypted Result
İstemci          → FHE.Decrypt(sk) → Sonuç (plaintext)

Ne zaman uygun?

  • ✅ Sunucuya hiçbir anahtar/secret vermeden arama yapmak istiyorsan (ör. çok kiracılı SaaS, gizli tıp verisi).
  • ✅ Karmaşık sorgular: WHERE age > 30 AND salary BETWEEN 5000 AND 10000.
  • ✅ Gelişmiş analitik (toplama, ortalama, ML inference) şifreli veride yapılacaksa.

Dikket ⛔

  • Çok yavaş (saniyeler–dakikalar/sorgu), özel donanım (GPU/FPGA) gerektirebilir.
  • Ciphertext boyutu 100–1000x büyür.
  • Uygulama karmaşıklığı çok yüksek (schema tasarımı, parametre seçimi, noise management).
  • Hala "production-ready" olma yolunda; kütüphaneler: OpenFHE, Concrete, SEAL, TFHE-rs.

📊 Hızlı Karşılaştırma

Özellik Blind Indexing Deterministic Enc. FHE
Desteklenen Sorgu = (eşitsiz) =, JOIN =, >, <, BETWEEN, LIKE, agg.
Performans 🚀 Çok hızlı (standart index) 🚀 Hızlı (standart index) 🐢 Çok yavaş (ms–sn–dk)
Depolama Ek Maliyeti +1 sütun (32–64 B) Yok (tek sütun) 📈 100–1000x
Güvenlik Modeli Sunucu indeks görür (HMAC) Sunucu ciphertext görür Sunucu hiçbir şey öğrenmez
Frekans Analizi Riski Orta (salt/pepper ile azalır) Yüksek Yok
Anahtar Yönetimi Uygulama tarafında secret Uygulama tarafında key Client-side key (pk/sk)
Uygulama Kolaylığı ✅ Kolay (ORM hook ile) ✅ Orta ❌ Zor (özel schema/kütüphane)
Tipik Kullanım PII arama (email, TC, telefon) FK/JOIN kolonları, düşük riskli PII Gizli analitik, çok kiracılı sıfır güven

🛠 Pratik Bir Seçim Rehberi

Benim kuralım: Basit başla, ihtiyaç arttıkça yükselt.

  1. Sadece "bu e-posta var mı?" soruyorsan → Blind Indexing (en az risk, en yüksek performans).
  2. Foreign key olarak şifreli kolon kullanacaksan veya JOIN gerekiyorsa → Deterministic Encryption (tek sütun, kolay entegrasyon).
  3. Sunucunun hiçbir şey bilmemesi gerekiyorsa (sıfır güven, düzenleyici zorunluluk) ve performans bütçen varsa → FHE (ama pilot/proje bazlı başla).

🗺 Mini Diyagram: Blind Indexing Akışı

flowchart LR
    A[Kullanıcı Verisi\n"ayse@example.com"] --> B[AES-GCM Şifreleme]
    A --> C[HMAC(secret, veri)\n→ Blind Index]
    B --> D[(Veritabanı\nencrypted_email)]
    C --> E[(Veritabanı\nemail_blind_idx\n+ B-tree Index)]
    F[Arama: "ayse@example.com"] --> G[HMAC(secret, sorgu)]
    G --> H[Index Lookup\nWHERE email_blind_idx = ?]
    H --> I[Eşleşen Row ID'ler]
    I --> J[encrypted_email'i Çek]
    J --> K[AES-GCM Çözme]
    K --> L[Sonuç Dön]

Ne oluyor burada?

  1. Veri iki yola gider: biri şifreleme, diğeri indeks.
  2. Arama sorgusu aynı secret ile blind index'e dönüştürülür.
  3. Veritabanı sadece indeks üzerinde arar — asıl şifreli veri dokunulmaz.
  4. Sonuç bulunan satırların şifreli verisi çekilip istemci tarafında çözülür.

Hangi yaklaşımı seçeceğine karar verirken tehdit modelini (kim ne görüyor?), sorgu karmaşıklığını (ne arıyorsun?) ve performans bütçeni (ne kadar gecikme tolere edersin?) yan yana koy. Çoğu ekip için Blind Indexing "iyi yeterince" güvenli ve operasyonel kolaylık sağlar. Daha ileri ihtiyaçlarda yukarı doğru tırmanırsın 🎯


🛠 Veri Hattında Uygulanabilir Mimarî Örneği

Merhaba! 👋 Hazırsan veri hattımızı adım adım inceleyelim. Düşün senin elinde bir veri akışı var: kaynak → güvenlik → şifreleme → indeksleme → tüketici. Her katman kendi sorumluluğunda, birbirinden bağımsız ama sorunsuz çalışıyor. Hadi pratik bir örnek üzerinden anlayalım 🚀

📦 Hatın Adımları

  • 🎯 Kaynak (Source) – Verinin nereden geldiği (ör. Kafka, RabbitMQ, HTTP endpoint).
  • 🔐 Güvenlik Katmanı – Kimlik doğrulama, yetkilendirme, rate-limiting.
  • 🔒 Şifreleme (Encryption) – Veri yolda ve depoda şifreli (AES‑256, TLS).
  • 🔍 İndeksleme (Indexing) – Arama/analitik için Elasticsearch, OpenSearch vb.
  • 📥 Tüketici (Consumer) – Son kullanıcıya veya downstream servise veri teslimi.

Her katman container içinde izole, Docker Compose ile bir arada ayağa kalkıyor. Böylece lokalde tek komutla docker compose up diyorsun ve hat çalışıyor ✨


🛠 Servis Kod Özetleri (Python)

Aşağıda her servisin çekirdek mantığını gösteren mini bir Python snippet var. Gerçek projede tabii ki daha fazla hata yakalama, loglama, config yönetimi eklersin.

1️⃣ encryption-service

# encryption_service/app.py
import os
from cryptography.fernet import Fernet

KEY = os.getenv("ENCRYPTION_KEY")  # 32‑byte base64
fernet = Fernet(KEY.encode())

def encrypt(payload: bytes) -> bytes:
    return fernet.encrypt(payload)

def decrypt(token: bytes) -> bytes:
    return fernet.decrypt(token)

if __name__ == "__main__":
    # Basit test
    data = b"gizli veri"
    enc = encrypt(data)
    print("Encrypted:", enc)
    print("Decrypted:", decrypt(enc))

2️⃣ indexer-service

# indexer_service/app.py
import json
from elasticsearch import Elasticsearch

es = Elasticsearch(os.getenv("ES_URL", "http://elasticsearch:9200"))

def index_document(index: str, doc: dict):
    resp = es.index(index=index, document=doc)
    return resp["_id"]

if __name__ == "__main__":
    sample = {"message": "merhaba dünya", "timestamp": "2024-01-01T00:00:00Z"}
    doc_id = index_document("logs", sample)
    print("Indexed with id:", doc_id)

3️⃣ consumer-service

# consumer_service/app.py
import pika, json

def callback(ch, method, properties, body):
    payload = json.loads(body)
    print("📥 Consumer received:", payload)
    # Burada iş mantığın olur (DB yaz, bildirim gönder, vs.)
    ch.basic_ack(delivery_tag=method.delivery_tag)

def main():
    conn = pika.BlockingConnection(pika.ConnectionParameters("rabbitmq"))
    channel = conn.channel()
    channel.queue_declare(queue="processed_data", durable=True)
    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue="processed_data", on_message_callback=callback)
    print("🚀 Consumer waiting for messages...")
    channel.start_consuming()

if __name__ == "__main__":
    main()

🐳 Docker Compose – Tüm Hati Tek Dosyada

version: "3.9"

services:
  # 1️⃣ Güvenlik katmanı (ör. OAuth2 Proxy) – basit bir placeholder
  auth-proxy:
    image: oauth2-proxy/oauth2-proxy:latest
    environment:
      OAUTH2_PROXY_PROVIDER: "oidc"
      OAUTH2_PROXY_OIDC_ISSUER_URL: "https://auth.example.com"
      OAUTH2_PROXY_CLIENT_ID: "${CLIENT_ID}"
      OAUTH2_PROXY_CLIENT_SECRET: "${CLIENT_SECRET}"
    ports:
      - "4180:4180"
    depends_on:
      - encryption-service

  # 2️⃣ Şifreleme servisi
  encryption-service:
    build: ./encryption_service
    environment:
      ENCRYPTION_KEY: "${ENCRYPTION_KEY}"
    expose:
      - "8000"
    depends_on:
      - indexer-service

  # 3️⃣ İndeksleme servisi
  indexer-service:
    build: ./indexer_service
    environment:
      ES_URL: "http://elasticsearch:9200"
    expose:
      - "8001"
    depends_on:
      - elasticsearch

  # 4️⃣ Tüketici servisi
  consumer-service:
    build: ./consumer_service
    environment:
      RABBITMQ_HOST: "rabbitmq"
    depends_on:
      - rabbitmq

  # Altyapı bileşenleri
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
    ports:
      - "9200:9200"
    volumes:
      - esdata:/usr/share/elasticsearch/data

  rabbitmq:
    image: rabbitmq:3.13-management
    ports:
      - "5672:5672"
      - "15672:15672"
    volumes:
      - rmqdata:/var/lib/rabbitmq

volumes:
  esdata:
  rmqdata:

Ne oluyor burada?

  • Her servis endişesiz birbirine bağımlı (depends_on).
  • auth-proxy trafiği yakalayıp kimlik doğrulaması yapıyor, sonra encryption-service’e yönlendiriyor.
  • Şifreleme sonrası veri indexer-service’e gidip Elasticsearch’e yazılıyor.
  • Son olarak consumer-service kuyruktan (RabbitMQ) alıp işliyor.

📐 Şema Özeti

[Client] → (HTTPS) → [auth-proxy] → [encryption-service] → [indexer-service] → [Elasticsearch]
                                                            ↓
                                                      [RabbitMQ] ← [consumer-service]
  • Oklar veri akış yönünü gösterir.
  • Parantez içi isimler Docker Compose’daki service isimleriyle birebir eşleşir.

Bu yapı küçük başlangıç için yeterli; ileride her servisi ayrı namespace’lere, Helm chart’larına, CI/CD pipeline’larına bölebilirsin. 🎉

İpucu: .env dosyana ENCRYPTION_KEY, CLIENT_ID, CLIENT_SECRET gibi sırları koy, repoya asla commit etme! 🔐

Hadi şimdi docker compose up -d diyip hatı canlıya alalım 🚢


📊 Performans ve Güvenlik Dengesi

Performans ve güvenlik arasında denge kurmak, veri hattınızın can damarıdır 🎯.
Her ekstra şifreleme katmanı gecikme getirir; ama hangi gecikmeyi tolere edebilirsiniz?

Neden bu trade‑off önemli? ⚡

  • Deterministik şifreleme (ör. AES‑GCM, SIV) → ≈ 5 ms gecikme.

    • Hızlı, düşük CPU, basit anahtar yönetimi.
    • Kullanım: Yüksek trafikli API’ler, gerçek‑zamanlı akışlar.
  • Tam Homomorfik Şifreleme (FHE) → ≈ 1 500 ms gecikme.

    • Veri hiç çözülmeden işlenir → maksimum gizlilik.
    • Kullanım: Hassas finansal/ sağlık analitik, çok az istek, yüksek güvenlik gerektiren batch işler.
  • Ara çözümler (Örn. Order‑Preserving Encryption, Secure Enclaves) → 10‑100 ms aralığı.

    • Belirli sorgular için yeterli gizlilik, daha düşük maliyet.

Kural: Gecikme bütçenizi ölçün, ardından o bütçeye sığan en güçlü şifrelemeyi seçin.

Hangi tekniği ne zaman seçersiniz? 🛡️

Senaryo Tercih Edilen Teknik Neden?
Gerçek‑zamanlı mesajlaşma, IoT telemetri Deterministik / AEAD < 10 ms gecikme, yüksek throughput
Kullanıcı verilerini analiz etmeden işleme (ML inference) FHE / MPC Veri asla açık olmaz, batch işlem toleranslı
Arama / sıralama gereken veritabanı sorguları Order‑Preserving / Structured Encryption Sorgu performansı korunur, kısmi gizlilik yeterli
Çok hassas finansal raporlama, nadir çalışan batch FHE Maksimum gizlilik, gecikme kabul edilebilir

Performans ölçümüne hızlı bir göz atalım 📈

Aşağıdaki Python benchmark betiği fikri, iki yöntemin (deterministik vs. FHE simülasyonu) ortalama gecikmesini karşılaştırmanıza yardımcı olur. Gerçek FHE kütüphanesi yerine time.sleep ile gecikme taklit edilmiştir; üretimde pyfhel, concrete vb. kullanılabilir.

import time
import statistics
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

# ---------- Deterministik şifreleme (AES‑GCM) ----------
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = b"123456789012"          # 12 byte nonce (gerçekte rastgele olmalı)
plaintext = b"benchmark data " * 100  # ~1.6 KB

def encrypt_aesgcm():
    return aesgcm.encrypt(nonce, plaintext, None)

# ---------- FHE benzetimi (yüksek gecikme) ----------
def encrypt_fhe_sim():
    # Gerçek FHE çağrısı buraya gelecek; şimdilik 1.5 s bekle
    time.sleep(1.5)
    return b"fake‑ciphertext"

# ---------- Benchmark yardımcı fonksiyonu ----------
def benchmark(func, runs=30):
    latencies = []
    for _ in range(runs):
        start = time.perf_counter()
        func()
        latencies.append((time.perf_counter() - start) * 1000)  # ms
    return {
        "ort": statistics.mean(latencies),
        "medyan": statistics.median(latencies),
        "stdev": statistics.stdev(latencies) if runs > 1 else 0,
    }

if __name__ == "__main__":
    print("🔐 AES‑GCM (deterministik) benchmark:")
    print(benchmark(encrypt_aesgcm))
    print("\n🧮 FHE simülasyonu benchmark:")
    print(benchmark(encrypt_fhe_sim))

Bu sayede ne oluyor?

  • Ortalama, medyan ve standart sapma ile gecikme dağılımını görürsünüz.
  • Farklı payload boyutları veya runs sayısı değiştirip senaryonuza en uygun tekniği veriyle kanıtlayabilirsiniz.

Özet 🎯

  • Gecikme bütçenizi netleştirin → 5 ms mı 1 500 ms mi?
  • Veri hassasiyeti ve işlem sıklığına göre şifreleme seçin.
  • Küçük bir Python benchmark ile varsayımlarınızı test edin, kararlarınızı veriye dayandırın.

Sonuç: Performans ve güvenlik birbirinin zıddı değil, doğru araç setiyle dengelenebilir bir sistem kurabilirsiniz ✅.


💻 Örnek Kod: Deterministik Şifreleme ve İndeks Oluşturma

Hazırsan başlayalım 🚀
Deterministik şifreleme, aynı girdi için her zaman aynı şifreleme sonucunu üretir. Bu sayede verileri arama / eşleştirme amacıyla indeksleyebiliriz, ama yine de düz metin olarak saklamamış oluruz.

Neden deterministik? 🤔

  • Arama performansı: Veritabanında WHERE email_enc = ? gibi sorgular çalıştırırsınız.
  • Tekrar eden veriler: Aynı e‑posta adresi her kayıtta aynı ciphertext’e dönüşür → duplicate detection kolaylaşır.
  • Güvenlik notu: Salt kayıt bazında sabitlenir (ör. record_id), böylece aynı değer farklı kayıtlarda farklı görünmez; ancak global salt kullanırsanız rainbow‑table saldırısı riski artar. Dikkatli olun ❗️

Python örneği 🐍

import os
import json
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

# ------------------------------
# Yardımcı: AES‑ECB (deterministik) + PKCS7 padding
# ------------------------------
def _aes_encrypt_deterministic(key: bytes, plaintext: bytes) -> bytes:
    """
    Aynı plaintext + aynı key → her zaman aynı ciphertext.
    ECB modu deterministik olur; IV kullanmıyoruz.
    """
    # PKCS7 padding (block size = 16)
    pad_len = 16 - (len(plaintext) % 16)
    padded = plaintext + bytes([pad_len]) * pad_len

    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
    encryptor = cipher.encryptor()
    return encryptor.update(padded) + encryptor.finalize()


# ------------------------------
# Ana fonksiyon: alan şifrele + indeks oluştur
# ------------------------------
def encrypt_and_index(record: dict, field: str, master_key: bytes, record_id: str) -> tuple[dict, dict]:
    """
    Args:
        record      : Orijinal kayıt (ör. {"email": "ali@example.com"})
        field       : Şifrelenecek alan adı ("email")
        master_key  : 32‑byte AES‑256 anahtarı (gizli, ortak değil!)
        record_id   : Kayıt için benzersiz kimlik (UUID, PK vb.)

    Returns:
        encrypted_record : Alanı şifrelenmiş haliyle yeni dict
        index_dict       : {field: {ciphertext_b64: record_id}} yapısı
    """
    # 1️⃣  Record‑specific salt = record_id (deterministik)
    #    Burada master_key'i doğrudan kullanıyoruz; isterseniz HKDF ile türetebilirsiniz.
    key = master_key  # basitlik için; prod’da key derivation önerilir

    # 2️⃣  Alan değerini al ve bytes’a çevir
    plain_value = record[field].encode("utf-8")

    # 3️⃣  Deterministik şifrele
    cipher_bytes = _aes_encrypt_deterministic(key, plain_value)
    cipher_b64 = base64.urlsafe_b64encode(cipher_bytes).decode("ascii")

    # 4️⃣  Yeni kayıt oluştur (orijinal alan yerine ciphertext)
    encrypted_record = record.copy()
    encrypted_record[field] = cipher_b64

    # 5️⃣  İndeks sözlüğü: ciphertext → record_id
    index_dict = {field: {cipher_b64: record_id}}

    return encrypted_record, index_dict


# ------------------------------
# 🎯 Kullanım örneği
# ------------------------------
if __name__ == "__main__":
    # 32‑byte (256‑bit) master key — **gerçek ortamda güvenli bir vault’tan alınmalı!**
    MASTER_KEY = os.urandom(32)

    veri = {"email": "ali@example.com"}
    record_id = "rec-001"

    sifreli, indeks = encrypt_and_index(veri, "email", MASTER_KEY, record_id)

    print("🔐 Şifrelenmiş kayıt :", json.dumps(sifreli, ensure_ascii=False))
    print("📇 İndeks            :", json.dumps(indeks, ensure_ascii=False))

Ne oluyor burada? 🛠

  1. Master key sabit, her kayıt için record_id salt görevi görür → aynı e‑posta her zaman aynı ciphertext’e dönüşür.
  2. encrypt_and_index fonksiyonu hem şifrelenmiş kaydı hem de arama indeksini döndürür.
  3. İndeks {"email": {"<ciphertext_b64>": "rec-001"}} şeklinde tutulduğunda, veritabanında email_enc kolonu üzerinden O(1) arama yaparsınız.

Küçük bir hatırlatma 📌

  • ECB modu deterministik ama pattern leakage riski taşır. Hassas verilerde AES‑SIV veya AES‑GCM‑SIV (deterministik authenticated encryption) tercih edin.
  • Master key’i asla kodda hard‑code etmeyin; HSM / Vault / KMS kullanın.

Artık elinizde deterministik şifreleme + indeks çifti var. Keyifli kodlamalar! ✅


🎯 GDPR/KVKK Uyumluluk İpuçları ve Denetim Hazırlığı

Veri hattında PII (kişisel tanımlayıcı veri) şifrelemek, hem GDPR hem de KVKK’nın “veri güvenliği” ve “veri sahibi hakları” maddelerini karşılamanın en doğrudan yoludur 🎯. Şifreleme sayesinde veri sızsa bile anlamlı olmaz; bu da ceza riskini ve itibar kaybını büyük oranda azaltır ✅.

Neden şifreleme yeterli değil, doğru şifreleme lazım? 🔐

  • En az dereceli gizlilik (Least‑privilege privacy): Sadece ihtiyaç duyan servisler plaintext görebilmeli. Diğer her yerde veri şifreli kalmalı.
  • Deterministik şifreleme: Aynı veri her zaman aynı ciphertext’e dönüşür. Böylece arama, join ve veri sahibi erişim/hak talep işlemleri (ör. “verimi sil”, “verimi göster”) kırılmadan çalışır.
  • Anahtar yönetimi (Key Management): Anahtarlar merkezi bir HSM/KMS’de tutulmalı, rotasyon politikası olmalı ve erişim logları denetlenebilmeli 🛠.
  • Erişim kontrolü & denetim izi: Her şifreleme/çözme işlemi audit log’a yazılmalı; “kim, ne zaman, hangi veriye erişti” sorusuna anında cevap verebilmelisiniz.

Kısaca: Veriyi şifrelemek yetmez; kim ne zaman çözebilir ve veri sahibi hakları nasıl desteklenir sorularına teknik cevap veren bir mimari kurun.


Denetime hazırlanmak için kontrol listesi 📋

Aşağıdaki maddeler, veri hattı akışınızı denetim (audit) öncesinde tek tek taramak için kullanabileceğiniz bir şablondur. Her madde için “Yapıldı / Yapılmadı / Kısmi” durumunu not edin ve kanıt (log, policy, test sonucu) toplayın.

{
  "auditChecklist": [
    {
      "id": "A-01",
      "title": "Etki Analizi (DPIA) Tamamlandı mı?",
      "status": "Yapıldı",
      "evidence": "DPIA raporu v1.3, tarih: 2024-03-12"
    },
    {
      "id": "A-02",
      "title": "Gizlilik Politikası Güncellendi mi?",
      "status": "Yapıldı",
      "evidence": "Web sitesi gizlilik politikası v2.1, onay tarihi: 2024-04-01"
    },
    {
      "id": "A-03",
      "title": "PII Şifreleme Stratejisi Belgelendi mi?",
      "status": "Kısmi",
      "evidence": "Şifreleme mimari diyagramı (v0.9), anahtar rotasyon planı eksik"
    },
    {
      "id": "A-04",
      "title": "Deterministik Şifreleme Kullanımı Test Edildi mi?",
      "status": "Yapılmadı",
      "evidence": ""
    },
    {
      "id": "A-05",
      "title": "Anahtar Yönetimi (KMS/HSM) Yapılandırıldı mı?",
      "status": "Yapıldı",
      "evidence": "AWS KMS key policy, rotasyon 90 gün, erişim logları CloudTrail"
    },
    {
      "id": "A-06",
      "title": "Veri Sahibi Hak Talep Süreci Otomatikleştirildi mi?",
      "status": "Kısmi",
      "evidence": "Silme API v1.0 hazır, düzeltme/hak erişim API’si geliştirme aşamasında"
    },
    {
      "id": "A-07",
      "title": "Denetim İzleri (Audit Logs) Saklanıyor mu?",
      "status": "Yapıldı",
      "evidence": "Elasticsearch cluster, 12 aylık retention, immutable index"
    },
    {
      "id": "A-08",
      "title": "Üçüncü Taraf Paylaşımları Sözleşmelerle Kapsandı mı?",
      "status": "Yapıldı",
      "evidence": "DPA imzalı tedarikçi listesi (PDF, 2024-02-20)"
    }
  ]
}

Son kontroller ⛔

  • Her madde için kanıt dosyasını (PDF, log export, test raporu) bir merkezi depoda (ör. S3 + versioning) toplayın.
  • Otomatik CI/CD içinde “audit‑ready” kapısı koyun: pipeline başarılı olmadan production’a geçmesin.
  • Yıllık/çeyreklik gözden geçirme takvimi oluşturun; bu listeyi canlı bir doküman gibi tutun 🛠.

Hazırsanız bu checklist’i bir sonraki sprintte Definition of Done’a ekleyin ve denetim günü geldiğinde “Her şey yolunda, kanıtlar burada” diyebilecek duruma gelin ✅.


💬 Son Söz ve Bir Sonraki Adım Önerisi

Hazırsan kısaca özetleyelim 🎯

Bu yazıda şunları gördük:

  • Veri şifrelemeyi arama performansını bozmadan nasıl entegre edebileceğimizi
  • Client-side vs server-side şifreleme stratejilerinin avantaj/dezavantajlarını
  • Searchable encryption (aranabilir şifreleme) tekniklerinin temellerini
  • Gerçek dünya senaryolarında key management ve rotation nasıl planlanır

❗️ Kritik nokta: Şifreleme bir "ekstra" değil, varsayılan olmalı. Arama özelliğini korurken veri hattı şifrelemesini başarmak, doğru araç seti ve mimari kararlarıyla tamamen mümkün.


🛠 Şimdi ne yapmalısın?

Hadi iş başa:
Şimdi, istediğiniz arama özelliğini korurken veri hattı şifrelemeyi nasıl başlatabileceğinizi öğrenin.

  1. Mevcut veri akışını haritala — nerede plaintext kalıyor?
  2. Threat model çiz: kimden, ne koruyorsun?
  3. Küçük bir pilot proje seç (ör. log indexi veya PII içeren alan)
  4. Client-side encryption + blind index kombinasyonunu test et
  5. Metrik topla: latency, storage overhead, developer experience

✅ Başarılı olursun: Veri sızması riski düşer, compliance kutucuğu dolur, arama hızı aynı kalır.


🔜 Bir sonraki adım

Makalede Desteklenen Yüksek Performanslı Aramalara Dalacağız — şifreli veriler üzerinde full-text search, fuzzy matching ve range query nasıl yapılır, hangi kütüphaneler (Bleve, Tantivy, OpenSearch plugins) işinize yarar ve benchmark sonuçları ne diyor? Görüşmek üzere! 👋


Bu içerik tamamen yapay zeka destekli otomasyon sistemi ile üretilmiştir.

Burak Sağlık

Burak Saglik

©2024 Desing and Developed by @Burak Sağlık

All rights reserved