Kriptografi ve Secret Yönetimi← İçindekiler Güvenli Kodlama Eğitimi

Kriptografi ve Secret Yönetimi

B

2020’de bir kripto para borsası, müşteri veritabanını şifrelemişti. Veriler AES-256 ile korunuyordu. Ama şifreleme anahtarı da aynı veritabanında, şifrelenmemiş bir tabloda duruyordu. Saldırgan veritabanına sızdığında, hem kasayı hem anahtarı aynı anda ele geçirdi. Şifreleme, anahtarsız bir kilit kadar işe yaradı: hiç.

Kriptografi, veriyi okunamaz hale getirip yalnızca doğru anahtara sahip kişinin okuyabilmesini sağlar. Ama yanlış kullanıldığında, sahte güvenlik hissi yaratır. Zayıf bir algoritmayla korunan sistem, şifresizden daha tehlikelidir. Çünkü şifresiz sistem en azından “korunmuyorum” der; zayıf şifreli sistem “güvendeyim” yalanını söyler.

Özlü kural: Kendi şifreleme algoritmanı yazma. Standart, test edilmiş, açık kriptografi kütüphaneleri kullan. Kendi kriptografini yazmak, güvenlik dünyasındaki en büyük ölümcül hatalardan biridir.

Hızlı ipucu: Kod tabanında grep -ri "md5\|sha1\|DES\|RC4\|ECB" . çalıştır. Çıkan her satırda kırılmış bir algoritma kullanılıyor olabilir.

55.1 Zayıf Şifreleme Algoritmaları

Bazı algoritmalar kırılmıştır ve artık güvenli değildir. Üretimde kullanılmaları yasaktır.

AlgoritmaTürDurumYerine ne
MD5HashKırıkSHA-256+ veya bcrypt/Argon2 (parola için)
SHA-1HashKırıkSHA-256 veya SHA-3
DESSimetrikKırık (56-bit anahtar)AES-256
3DESSimetrikKullanımdan kalkıyorAES-256
RC4SimetrikKırıkAES-256-GCM veya ChaCha20
RSA-1024AsimetrikZayıfRSA-2048+ veya ECDSA
ECB modeModKırık (desen sızdırır)GCM veya CBC+HMAC

55.2 Veri Şifreleme (Rest vs Transit)

Veriyi iki yerde şifrelemen gerekir: dururken (at rest) ve hareket halindeyken (in transit).

Transit (Hareket Halinde): TLS

Veri ağ üzerinden giderken TLS ile şifrelenir. HTTPS, TLS’nin web’deki kullanımıdır.

# Python requests ile TLS baglantisi
import requests

# DOGRU: HTTPS kullan + sertifika dogrulama acik (varsayilan) + timeout
response = requests.get('https://api.example.com/data', timeout=10)
# requests varsayilan olarak sertifikasi dogrular

# KOTU: TLS dogrulamayi kapatma (ASLA!)
response = requests.get('https://api.example.com/data', verify=False)
# verify=False, "herhangi bir sertifikasi kabul et" demek
# Ortadaki adam saldirisina acik

Rest (Dururken): Uygulama Seviyesinde Şifreleme

Veritabanında saklanan hassas veriler (T.C. No, kredi kartı, sağlık kaydı) uygulama seviyesinde şifrelenmelidir. Veritabanı şifrelemesi (TDE - Transparent Data Encryption) disk seviyesinde korur ama veritabanına sızan biri tüm veriyi okuyabilir.

from cryptography.fernet import Fernet

# 1. Anahtar uret (TEK SEFER, guvenli yerde sakla)
# Bu anahtar veritabaninda DEGIL, KMS veya environment variable'da
key = Fernet.generate_key()  # 256-bit symmetric key
fernet = Fernet(key)

# 2. Hassas veriyi sifrele
def encrypt_tc_no(tc_no: str) -> bytes:
    """TC Kimlik No'yu veritabanina kaydetmeden once sifrele"""
    return fernet.encrypt(tc_no.encode('utf-8'))

# 3. Sifreyi coz (sadece uygulama icinde)
def decrypt_tc_no(encrypted: bytes) -> str:
    return fernet.decrypt(encrypted).decode('utf-8')

# Kullanim
encrypted_tc = encrypt_tc_no("12345678901")
db.execute(
    "INSERT INTO citizens (tc_no_encrypted) VALUES (?)",
    (encrypted_tc,)
)

# Okuma
row = db.execute("SELECT tc_no_encrypted FROM citizens WHERE id = ?", (user_id,))
tc_no = decrypt_tc_no(row['tc_no_encrypted'])

Fernet nedir? Python cryptography kütüphanesinin sağladığı, AES-128-CBC + HMAC-SHA256 kullanan yüksek seviyeli bir şifreleme API’sidir. Şifreleme + bütünlük kontrolü tek turda yapar. Anahtar üretimi, IV üretimi, zaman damgası otomatiktir. “Yanlış kullanma” ihtimalini en aza indirir.

AES-GCM ile Daha İnce Kontrol

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

# 256-bit anahtar uret
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)

# Sifrele
# nonce: her sifreleme icin BENZERSIZ olmali (asla tekrar kullanma!)
# 96-bit nonce standarttir
nonce = os.urandom(12)
plaintext = "Gizli mesaj".encode('utf-8')
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data=None)

# Coz
decrypted = aesgcm.decrypt(nonce, ciphertext, associated_data=None)
Veritabanı şifrelemesi (TDE) yeterli mi?

Hayır. TDE (Transparent Data Encryption) disk seviyesinde şifreler. Disk fiziksel olarak çalınırsa veri korunur. Ama saldırgan veritabanına SQL injection ile sızarsa, TDE bir işe yaramaz çünkü veritabanı şifreyi çözmüş halde verir. Uygulama seviyesi şifreleme, veritabanına yazılmadan önce şifreler. Sızan saldırgan şifreli veriyi görür, anahtarsız okuyamaz. İkisini birlikte kullan: TDE disk için, uygulama şifrelemesi veri için.

55.3 Koddaki Secret’lar

En yaygın ve en tehlikeli güvenlik hatası: API anahtarları, parolalar ve bağlantı string’lerinin koda gömülmesidir.

Kötü Kod (Kırılgan)

# KODDA SECRET BIRAKMA - ASLA!
API_KEY = "sk-1234567890abcdef"
DB_PASSWORD = "SuperSecret123!"
AWS_SECRET = "wJalrXUt+something"
JWT_SECRET = "my-secret-key"

# Bu kod git history'sine islenir
# Git gecmisinden silmek neredeyse imkansizdir
# GitHub'a push edersen, bot'lar dakikalar icinde yakalar

Doğru Yaklaşım: Environment Variables

import os

# Environment variable'dan oku
# .env dosyasi git'e commit EDILMEZ (.gitignore'a ekle!)
API_KEY = os.environ['API_KEY']
DB_PASSWORD = os.environ['DB_PASSWORD']
JWT_SECRET = os.environ['JWT_SECRET']

# Varsayilan deger VERME (production'da yanlislikla varsayilan calismasin)
# KOTU: API_KEY = os.environ.get('API_KEY', 'default-key')
# IYI: KeyError firlat, eksik secret uygulama baslamasin

.env dosyası:

# .env (bu dosya .gitignore'da OLMALI)
API_KEY=sk-real-key-from-aws-secrets-manager
DB_PASSWORD=strong-password-here
JWT_SECRET=32-byte-random-string-here

.gitignore:

.env
.env.*
*.pem
*.key

Daha İyi: Vault Çözümleri

Environment variables da sızabilir (process listesi, crash dump, loglar). Daha güvenli yöntem, secret’ları merkezi bir vault’ta tutmak:

# HashiCorp Vault ornegi
import hvac

# Vault'a baglan
client = hvac.Client(
    url='https://vault.internal:8200',
    token=os.environ['VAULT_TOKEN']  # Sadece bu tek secret env'de
)

# Secret'i Vault'tan dinamik olarak oku
secret = client.secrets.kv.read_secret_version(
    path='database/production',
    mount_point='secret'
)
db_password = secret['data']['data']['password']

Vault’un avantajları:

  • Secret’lar loglanmaz (sadece erişim loglanır)
  • Dinamik secret üretimi (her istekte yeni parola)
  • Otomatik rotasyon (30 günde bir parola değişir)
  • Audit trail (kim, ne zaman, hangi secret’a erişti)
Bunu Yap
  • Secret'ları environment variable veya Vault'ta sakla
  • .env dosyasını .gitignore'a ekle
  • Secret olmadan uygulama başlamasın (fail-fast)
  • Secret'ları periyodik olarak rotate et
Bunu Yapma
  • API anahtarını koda göm
  • Secret'ı varsayılan değerle bırak
  • .env dosyasını commit et
  • Secret'ı logla veya hata mesajında göster

55.4 Key Management

Şifreleme anahtarları, şifrelenmiş veriden daha değerlidir. Anahtarınız sızarsa, tüm şifreli veri deşifre olur. Anahtar yönetimi şifrelemeden daha zor ve daha önemlidir.

Anahtar Üretimi

import secrets

# KRIPTOGRAFIK GUVENLI rastgele bytes uret
# random module KULLANMA (tahmin edilebilir)
# secrets module isletim sistemi entropy kaynagini kullanir

# 256-bit (32 byte) symmetric key
symmetric_key = secrets.token_bytes(32)

# 128-bit (16 byte) API key (URL-safe string)
api_key = secrets.token_urlsafe(16)

# UUID (genel benzersiz ID)
unique_id = secrets.token_hex(16)

Anahtar Rotasyonu

Anahtar sonsuza kadar aynı kalmamalıdır. Sızma şüphesi olmasa bile, periyodik rotasyon şarttır:

# Anahtar rotasyon stratejisi
# 1. Yeni anahtar uret
# 2. Yeni veriler yeni anahtarla sifrelenir
# 3. Eski veriler talep geldikce yeni anahtarla yeniden sifrelenir
# 4. Tum veri migrate edildiginde eski anahtar imha edilir

# Anahtar versiyonlama
key_versions = {
    'v1': old_encryption_key,  # read-only (gecis donemi)
    'v2': current_encryption_key,  # read + write
}

def encrypt_data(plaintext: bytes) -> tuple:
    """Veriyi mevcut anahtarla sifrele, versiyonu ile birlikte dondur"""
    version = 'v2'
    ciphertext = encrypt_with_key(key_versions[version], plaintext)
    return (version, ciphertext)  # versiyon da kaydedilir

def decrypt_data(version: str, ciphertext: bytes) -> bytes:
    """Dogru versiyondaki anahtarla coz"""
    key = key_versions[version]
    return decrypt_with_key(key, ciphertext)

HSM (Hardware Security Module)

En yüksek seviye anahtar koruması HSM’dir. HSM, anahtarları fiziksel olarak koruyan donanım modülüdür. Anahtar HSM’den asla çıkmaz; tüm şifreleme işlemleri HSM içinde yapılır. Bankacılık, devlet ve askeri sistemlerde kullanılır.

Cloud alternatifleri:

  • AWS KMS (Key Management Service)
  • Google Cloud KMS
  • Azure Key Vault
  • HashiCorp Vault (self-hosted)

55.5 Secret Tarama Araçları

Koda gömülmüş secret’ları otomatik tespit eden araçlar:

truffleHog: Git reposundaki commit tarihçesini tarar, yüksek entropili string’leri ve bilinen pattern’leri (AWS key, Stripe key, etc.) arar.

# truffleHog ile repo tara
trufflehog git https://github.com/company/repo.git

# Tum commit tarihcesini tarar
# Sizdirmis oldugunuz bir secret 2 yil once bile olsa bulur

git-secrets: AWS tarafından geliştirildi. Pre-commit hook olarak çalışır. Commit yapmadan önce çalışır ve secret varsa commit’i engeller.

# git-secrets kurulumu
git secrets --install
git secrets --register-aws

# Pre-commit hook olarak calisir
# Commit sirasinda AWS key pattern kontrolu yapar
# Eslesme varsa commit reddedilir

pre-commit ile otomatik koruma:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/trufflesecurity/trufflehog
    rev: v3.0.0
    hooks:
      - id: trufflehog
        args: ['--no-update', '--fail-verified', 'git', 'file://.']

  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']

Bu yapılandırma ile her git commit öncesinde otomatik olarak secret taraması yapılır. Secret bulunursa commit engellenir. Geliştirici yanlışlıkla bile secret push edemez.

Secret'ı git history'sinden nasıl silerim?

Bir secret’ı commit ettiysen ve sonra sildin, git history’sinde hâlâ durur. git rm veya sonraki commit’te silme, history’den kaldırmaz. Çözüm: git filter-branch veya daha hızlı BFG Repo-Cleaner kullan. Ama bu, tüm commit hash’lerini değiştirir. Herkesin yeniden clone yapması gerekir. En iyi çözüm: secret’ı rotate et (yeni anahtar üret, eskisini iptal et). Eski secret history’de kalsa bile artık işe yaramaz.

Senaryo: AWS Anahtarı Sızıntısı

Bir geliştirici, AWS access key’i kod içinde bırakıp GitHub public reposuna pushladı. 4 dakika sonra otomatik bir bot, anahtarı tespit etti. Bot, AWS hesabına giriş yaptı, 50 EC2 instance (büyük sunucu) açtı ve kripto para madenciliği başlattı. 6 saat sonra AWS alarm verdiğinde fatura 14.000 dolardı. Çözüm: AWS console’dan anahtarı iptal et (1 dakika), instance’ları kapat (5 dakika), AWS support’a başvur (fatura affı için). Ama daha önemlisi: pre-commit hook ile bunu en baştan engellemek. Secret tarama araçları, bu senaryoyu commit aşamasında durdururdu.

Kriptografi ve Secret Yönetimi Kontrol Listesi
  • MD5, SHA-1, DES, RC4, ECB mod kullanılmıyor
  • Veri at rest: AES-256-GCM veya Fernet ile şifreli
  • Veri in transit: TLS kullanılıyor, verify=False yok
  • Kodda hardcoded secret yok
  • Secret’lar environment variable veya Vault’ta
  • .env .gitignore’da
  • pre-commit hook ile secret tarama otomatik
  • Anahtar rotasyon politikası tanımlı (örn. 90 günde bir)
  • Kriptografik rastgelelik için secrets modülü kullanılıyor

Gerçek olay: 2020’de bir kripto para borsası olan Ledger, müşteri veritabanını sızdırdı. 270.000 kişinin adı, adresi ve e-postası darknet’te satışa çıktı. Ama asıl sorun, sızan veride müşterilerin geçmiş sipariş “not” alanında mnemonik kelimeler (kripto cüzdan kurtarma kelimeleri) vardı. Yani şifreleme vardı ama anahtar yönetimi hatalıydı: anahtar, veriyle aynı veritabanındaydı. Sonuç: milyonlarca dolarlık kripto para çalındı. Ders: anahtar, kilitli kapının yanında duruyorsa, kilit işe yaramaz.

Benzetme: Kriptografi, bir kasadır. Kasanın sağlamlığı, kasayı üreten firmanın (AES, RSA) kalitesine bağlıdır. Kendi kasanı yapmaya çalışma. Anahtar yönetimi ise kasanın anahtarını nerede sakladığındır. Anahtarı kasanın üstüne bantlamak (koda gömmek), anahtarı güvenli kutuda (Vault) saklamaktan çok daha risklidir.

İlgili Bölümler