
Tue Oct 06 2026

Merhaba! 👋
Benimle birlikte veri güvenliğinin kalbi olan şifreleme stratejilerine dalalım mı?
Geçen yıl bir mikro‑hizmet projesinde “tüm veriyi sunucuda şifreleriz, sorun olmaz” diyorduk. Ancak bir gün müşteri “veri hiçbir zaman sunucumuza gelmemeli” dediğinde, istemci‑tarafı şifrelemeye geçmek zorunda kaldık. Planlamadan önce tehdit modelini çizmek bizi haftalarce yeniden yazım zahmetinden kurtardı.
Özetle: Doğru şifreleme stratejisi, güvenlik, performans ve yasasal risk üçgenini dengeleyen tek taşıdır. Hazırsan, beraber derinlemesine inceleyelim! 🚀
Hazırsan başlayalım 🚀
Şifreleme dünyasında üç ana yaklaşımla karşılaşırsınız: simetrik, asimetrik ve uçtan uç (E2EE). Her birinin kendine has avantajları, dezavantajları ve kullanım senaryoları var. Hadi tek tek inceleyelim.
Tek bir anahtar hem şifrelemek hem de çözmek için kullanılır.
| ✅ Avantajlar | ❌ Dezavantajlar |
|---|---|
| Çok hızlı, düşük CPU yükü 🎯 | Anahtar dağıtımı zordur; her iki taraf da aynı anahtarı güvenli bir şekilde almalı |
| Basit implementasyon, küçük veri blokları için ideal | Anahtar ele geçirilirse tüm iletişim tehlikeye girer |
| Donanım hızlandırıcıları (AES‑NI) ile çok performanslı | Büyük sistemlerde anahtar yönetimi karmaşıklaşır |
Ne zaman kullanmalı?
Örnek senaryo:
Bir mesajlaşma uygulamasında kullanıcıların cihazlarında saklanan medya dosyalarını (fotoğraf, video) şifrelemek için AES‑256 gibi bir simetrik algoritma tercih edersiniz. Anahtarı cihazda tutarsınız, sunucu asla görmez.
İki farklı anahtar: public key (herkesle paylaşılır) ile şifreleme, private key (sadece sahibinde) ile çözme.
| ✅ Avantajlar | ❌ Dezavantajlar |
|---|---|
| Anahtar dağıtımı kolay; public key açıkça paylaşılabilir 🔁 | Simetriğe göre çok daha yavaş (CPU yoğun) |
| Kimlik doğrulama ve dijital imza için temel | Büyük veri bloklarını doğrudan şiflemek pratik değil |
| PKI altyapısı ile güven zinciri kurulabilir | Anahtar yönetimi (sertifika yenileme, iptal) ekstra iş yükü getirir |
Ne zaman kullanmalı?
Örnek senaryo:
Bir dosya depolama servisinde kullanıcı dosyasını yüklerken, sunucu kullanıcının public key’i ile dosyayı şifreler. Sadece kullanıcının private key’i dosyayı açabilir. Sunucu asla içeriği göremez.
Gerçek hayatta en yaygın kullanılan model: asimetrik ile oturum anahtarı değiştirilir, ardından simetrik ile veri şifrelenir.
| ✅ Neden tercih edilir? |
|---|
| Asimetrik’in güvenli anahtar değişimi + Simetrik’in hızı bir arada 🎯 |
| TLS, Signal Protokolü, WhatsApp, Signal, Telegram (secret chats) hepsi bu mantıkla çalışır |
Basit akış:
Veri, gönderici cihazından alıcı cihazına kadar hiçbir ara sunucu tarafından çözülemez.
| 🎯 Temel Özellikler |
|---|
| Anahtarlar sadece uç cihazlarda üretilir ve saklanır. |
| Sunucu sadece şifreli blob taşır; metadata (kim‑kime, zaman) dışında içerik göremez. |
| Forward Secrecy (ileri gizlilik) için her oturumda yeni anahtar çiftleri (ratchet) kullanılır. |
Avantajları
Dezavantajları
Örnek senaryolar
| Senaryo | Önerilen Yaklaşım |
|---|---|
| Yüksek performanslı iç veri akışı (microservice‑to‑microservice) | Simetrik (AES‑GCM) + güvenli anahtar dağıtımı (Vault, KMS) |
| İlk el sıkışma / kimlik doğrulama (TLS, API auth) | Asimetrik (ECDSA, Ed25519) |
| Kullanıcı verileri sunucuda saklanıyor ama sunucu okumamalı | Hibrit + E2EE (Signal protokolü) |
| Yasal/uyumluluk gereksinimi: veri hiçbir yerde düz metin olmamalı | Tam E2EE (istemci tarafında anahtar üretimi, yedekleme şifreli) |
Anahtar yönetimi her zaman en zayıf halinizdir.
- Simetrik: Anahtarı HSM/KMS’te saklayın, rotasyon politikası koyun.
- Asimetrik: Private key’i hiçbir zaman sunucuya koymayın; sadece public key paylaşın.
- E2EE: Kullanıcıya yedekleme kodu (recovery phrase) verin, ama bunu da şifreleyerek saklayın.
Özetle:
Hangi senaryo sizin projenize en uygun? 🤔
Kod tarafında bir anahtar değişimi örneği isterseniz bir sonraki bölümde crypto.subtle (Web Crypto API) ile küçük bir demo yazabiliriz. Hazır mısınız? 🚀
Hazırsan başlayalım. 🧭 İstemci taraflı şifreleme, ham veriyi cihazda, yani güvenilir olarak bildiğimiz istemci tarafında kilitleyen ve ancak bu cihaz anahtarını bilen tarafın daha sonra açabildiği bir yöntem. Ne oluyor burada? 🎯
[İstemci (Web) ] --> Anahtar üretimi (Web Crypto API) --> Şifrele (AES‑GCM) --> [Şifrelenmiş veri + iv]
| |
| v
| Sunucuya aktarım (HTTPS)
| |
v v
[Kullanıcı Girişi] [Sunucu Yeniden Oluşturabilir / İşleyebilir]
| |
| v
| [İstemci Anahtarı Alınır]
v |
[Anahtarı Sakla/Şifrele] [Çöz (AES‑GCM)]
<-- [Şifresiz Veri] <--
Bu şema, güç merkezini sunucudan istemciye taşıdığımızı gösteriyor – güvenilmez bir ortamda bile doğru şekilde güvende kalıyoruz.
Ne yapıyoruz? 🌟 Kısa bir metin alıyoruz, tarayıcıda bir anahtar ve iv oluşturuyoruz, ardından veri yoluyla gidiyoruz. Anahtarları saklamıyoruz (gerçek dünyadaki gibi), sadece gönderilen veriler ve iv’yi göndermemiz gerekiyor.
// Tarayıcı ortamında çalışır (Web Crypto API)
async function encryptMessage(plaintext, key) {
// 1️⃣ Rastgele bir iv üret (12 byte'lık GCM için yeterli)
const iv = crypto.getRandomValues(new Uint8Array(12));
// 2️⃣ Anahtarı CryptoKey formatına dönüştür (base64'ten JSON'a)
const importedKey = await crypto.subtle.importKey(
'raw',
key, // ArrayBuffer (örneğin Uint8Array)
{ name: 'AES-GCM' },
false,
['encrypt']
);
// 3️⃣ Şifrele
const encoded = new TextEncoder().encode(plaintext);
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
importedKey,
encoded
);
// 4️⃣ `iv + ciphertext` geri döndür (bundan sonra istenirse anahtar yok)
const result = new Uint8Array(iv.length + ciphertext.byteLength);
result.set(iv, 0);
result.set(new Uint8Array(ciphertext), iv.length);
return result.buffer;
}
// -----------------------------------------------------------------
// Örnek kullanım (anahtar 32 byte'lık rastgele bir dizi)
const rawKey = crypto.getRandomValues(new Uint8Array(32));
const myText = 'Merhaba, Dünya!';
encryptMessage(myText, rawKey).then(buf => {
// Giden veri: iv + şifrelenmiş veri (base64 string olarak kullanışlı)
const b64 = btoa(String.fromCharCode(...new Uint8Array(buf)));
console.log('Şifrelenmiş Veri (b64):', b64);
});
Bu sayede ne oluyor? ✅ Tarayıcı bir anahtar ve iv oluşturuyor, veriyi şifreliyor ve anahtar olmadan sunucu tarafına gönderiyor. Bunu alan taraf, iv’i ayırıp şifrelenmiş veriyi depolayabiliyor; ancak veriyi açmak için de cihazda bulunması gereken anahtara ihtiyaç var.
Umarım bunlar, istemci taraflı şifreleme akışını daha somut bir şekilde anlamanıza yardımcı olur. Hadi bir sonraki bölümde uygulama notlarına dalalım! 🚀
Sunucu taraflı şifreleme (SSE), verinin sunucuya ulaştığı an şifrelenmesini ve saklanmasını sağlar. Kullanıcı veya uygulama hiçbir ek işlem yapmaz; tüm ağırlık altyapı tarafından taşınır. Süreci üç ana adıma bölebiliriz:
Veri gelince şifreleme 📥
Anahtar depolama ve yaşam döngüsü 🔐
Erişim kontrolü ve denetim 🛡️
| Senaryo | Şifreleme Türü | Anahtar Yönetimi | Avantaj | Risk |
|---|---|---|---|---|
| S3 (AWS) | SSE‑S3, SSE‑KMS, SSE‑C | AWS yönetir / Müşteri yönetir | Kolay etkinleştirme, merkezi IAM | Sunucu/AWS hesabı tehlikeye girerse veri de tehlikede |
| Azure Blob | SSE (Microsoft‑managed), SSE‑CMK | Microsoft / Müşteri (Key Vault) | Azure RBAC ile ince taneli kontrol | Aynı risk: abonelik/tenant ihlali = veri ihlali |
| SQL Server / Azure SQL | TDE (Transparent Data Encryption) | Microsoft / Müşteri (Key Vault) | Uygulama değişikliği yok, saydam | Master key / TDE protector kaybedilirse veri kurtarılamaz |
| SaaS (ör. Salesforce, ServiceNow) | Platform‑managed encryption | Sağlayıcı yönetir | Sıfır opsiyonel yapılandırma | Veri sahipliği sağlayıcıda, uyumluluk kısıtlamaları olabilir |
Özet:
Aşağıdaki komutlar bir bucket’ın varsayılan şifreleme ayarlarını günceller. İlk komut SSE‑S3 (AWS yöneten anahtar), ikincisi SSE‑KMS (kendi KMS anahtarınız) kullanır.
# 1️⃣ SSE‑S3 (AWS‑managed) varsayılan şifrelemeyi aç
aws s3api put-bucket-encryption \
--bucket my-secure-bucket \
--server-side-encryption-configuration '{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
}'
# 2️⃣ SSE‑KMS (Customer‑managed) varsayılan şifrelemeyi aç
aws s3api put-bucket-encryption \
--bucket my-secure-bucket \
--server-side-encryption-configuration '{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-7890-abcd-ef1234567890"
}
}
]
}'
Ne oluyor burada?
put-bucket-encryption bucket’a varsayılan şifreleme politikası yazar.AES256 → SSE‑S3, AWS anahtarı üretir ve döndürür.aws:kms + KMSMasterKeyID → SSE‑KMS, kendi KMS anahtarınızı kullanır; IAM politikalarıyla kim bu anahtarı kullanabileceğini kontrol edersiniz.cp ile kopyalayıp üzerine yazabilirsiniz).Küçük hatırlatma: Sunucu taraflı şifreleme veri hareket halindeyken (in‑flight) TLS ile, dinlenirken (at‑rest) ise bu mekanizmalarla korunur. Her iki katmanı da etkin tutmak, defence‑in‑depth stratejisinin vazgeçilmez bir parçasıdır 🚀.
Anahtar yönetimi, güvenliğin kalp atışı gibidir — sürekli, düzenli ve hatasız olmalı. İki yaygın mimari için (Merkezi KMS vs. Donanım Güvenlik Modülü/HSM) yaşam döngüsünü adım adım inceleyelim.
| Mimari | Dağıtım Yöntemi | Depolama |
|---|---|---|
| KMS | IAM rolleri / politikalarla erişim kontrolü | Yönetilen, yüksek oranda kullanılabilir depoda (encrypted at rest) |
| HSM | PKCS#11 / JCE arayüzleri üzerinden uygulama tarafında | HSM içi tampon bellek; dışa çıkmaz, yedekleme için özel yöntemler |
GenerateDataKey).Deny koyarak anında engelle.kms:* yetkisine sahip.Encrypt, Decrypt, GenerateDataKey izinleri ver.import boto3
import base64
from cryptography.fernet import Fernet
# KMS istemcisi
kms = boto3.client('kms', region_name='eu-west-1')
KEY_ID = 'alias/my-app-master-key' # Master key alias/ARN
def generate_data_key():
"""KMS'ten 256‑bit Data Key (plaintext + ciphertext) al."""
resp = kms.generate_data_key(KeyId=KEY_ID, KeySpec='AES_256')
plaintext_key = resp['Plaintext'] # bytes
ciphertext_key = resp['CiphertextBlob'] # bytes (KMS ile şifrelenmiş)
return plaintext_key, ciphertext_key
def encrypt_data(plaintext: bytes, data_key: bytes) -> bytes:
"""Fernet (AES‑GCM) ile veri şifrele."""
f = Fernet(base64.urlsafe_b64encode(data_key))
return f.encrypt(plaintext)
def decrypt_data(ciphertext: bytes, data_key: bytes) -> bytes:
f = Fernet(base64.urlsafe_b64encode(data_key))
return f.decrypt(ciphertext)
# ---- Kullanım akışı ----
# 1️⃣ Data Key üret
plain_dk, wrapped_dk = generate_data_key()
# 2️⃣ Veriyi şifrele (plaintext data key ile)
secret = b"Gizli API anahtarı 🚀"
encrypted = encrypt_data(secret, plain_dk)
print("Şifreli veri:", base64.b64encode(encrypted).decode())
# 3️⃣ Data Key'i güvenli bir yerde sakla (wrapped_dk) – veritabanı, S3 vb.
# Plaintext key'i **asla** diskine yazma! Bellekten sil:
del plain_dk
# 4️⃣ Çözme zamanında: wrapped_dk'yi KMS'e gönder → plaintext al
response = kms.decrypt(CiphertextBlob=wrapped_dk)
recovered_dk = response['Plaintext']
# 5️⃣ Veriyi çöz
decrypted = decrypt_data(encrypted, recovered_dk)
print("Çözülmüş veri:", decrypted.decode())
Ne oluyor burada?
generate_data_key → KMS hem plaintext (şifreleme için) hem ciphertext (saklama için) DK verir.Hazırsan küçük, orta ve büyük veri senaryolarını yan yana koyalım. Aşağıdaki tablo, CPU/GPU yükü, gecikme, ağ bant genişliği, depolama overhead ve operasyonel maliyet gibi kritik metrikleri özetler. Sayılar yaklaşık değerlerdir; kendi ortamına göre çekip düzeltmek en iyisidir 🎯
| Metrik | 📱 Mobil Uygulama (Küçük Veri) | 🌐 IoT (Orta Veri) | 🏢 Enterprise Data Lake (Büyük Veri) |
|---|---|---|---|
| CPU/GPU Yükü | %5‑15 (tek iş parçacığı) | %30‑60 (paralel işlem) | %70‑95 (cluster‑wide, GPU hızlandırma) |
| Gecikme (ms) | 20‑80 (edge cache) | 50‑200 (regional gateway) | 100‑500 (multi‑region replication) |
| Ağ Bant Genişliği (Mbps) | 1‑5 (JSON/Protobuf) | 10‑100 (MQTT/CoAP batch) | 1 000‑10 000 (Parquet/ORC stream) |
| Depolama Overhead (%) | 5‑10 (metadata + index) | 15‑25 (time‑series compaction) | 30‑50 (erasure coding + snapshots) |
| Operasyonel Maliyet (USD/ay) | 10‑50 (serverless + CDN) | 200‑1 000 (K8s + managed DB) | 5 000‑50 000+ (dedicated cluster + backup) |
Maliyet Formülü
Toplam Maliyet = (CPU_Saat × CPU_Fiyat) + (GPU_Saat × GPU_Fiyat) + (Depolama_GB × Depolama_Fiyat) + (Ağ_GB × Ağ_Fiyat)
👉 Kendi cloud sağlayıcının fiyat listesini koy, aylık tahmin al.
Ölçeklenebilirlik Oranı
Ölçeklenebilirlik = (Maksimum Yük / Ortalama Yük) × 100
👉 200 % üzeri → auto‑scaling zorunlu.
Gecikme Bütçesi
İzin Verilen Max Gecikme = Kullanıcı Deneyimi Hedefi – Ağ Gecikmesi – İşlem Süresi
👉 Mobilde <100 ms, IoT <300 ms, Data Lake <1 s hedefle.
Depolama Verimliliği
Etkili Depolama = Ham Veri × (1 + Overhead/100)
👉 Parquet/ORC + sıkıştırma → overhead %10‑15'e düşürülebilir.
Ne oluyor burada?
Kendi senaryonu tabloya yerleştir, formülleri uygula ve hangi metrik sence "darboğaz" olduğunu belirle. Sonra o metrik üzerine optimizasyon odaklan — böylece hem performans hem maliyet dengelenmiş bir mimari elde edersin ✅
Hazır mısın? Hadi başlayalım. 🎯
| Standard | Ne istiyor? | Şifreleme etkisi |
|---|---|---|
| GDPR | Kişisel verinin “uygun teknik ve organizasyonel önlemlerle” korunması | AES‑256 (data‑at‑rest) + TLS 1.3 (data‑in‑transit) zorunlu hale gelir. Anahtar yönetimi için HSM/KMS önerilir. |
| KVKK | Veri işleyenlerin “gizlilik ve güvenlik” sağlayıp kanıtlaması | GDPR ile benzer; ek olarak veri yerelliği (data residency) şartı getirebilir → şifreleme anahtarları Türkiye’de tutulmalı. |
| HIPAA | Sağlık verisi (ePHI) için “şifreleme ya da eşdeğer koruma” | AES‑256 + audit‑ready loglama; anahtar rotasyonu 90 günde bir. |
| PCI‑DSS | Kart verisi (CHD) için “şifreleme, tokenizasyon veya maskeleme” | AES‑256 + tokenization; anahtar ayrımı (KEK/DEK) ve split‑knowledge zorunlu. |
Özet: Her standard AES‑256’yı baz alıyor ama anahtar yaşam döngüsü, depolama konumu ve loglama detayları farklılık gösteriyor. 🔐
| Mimari | Spoofing | Tampering | Repudiation | Information Disclosure | Denial of Service | Elevation of Privilege |
|---|---|---|---|---|---|---|
| Monolitik VM | ❌ (tek giriş noktası) | ✅ (WAF + IMDS) | ✅ (merkezi log) | ✅ (disk şifreleme) | ⚠️ (tek hata noktası) | ⚠️ (root erişim) |
| Mikroservis (K8s) | ✅ (mTLS + SPIFFE) | ✅ (PodSecurityPolicy) | ✅ (distributed tracing) | ✅ (sidecar proxy şifreleme) | ✅ (HPA + PodDisruptionBudget) | ✅ (RBAC + OPA) |
| Serverless (FaaS) | ✅ (IAM + signed URLs) | ✅ (immutable deploy) | ✅ (cloud audit logs) | ✅ (managed encryption) | ✅ (auto‑scale) | ⚠️ (over‑privileged roles) |
Ne anlıyoruz?
# örnek: Fluent Bit + Loki yapılandırması
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
data:
fluent-bit.conf: |
[SERVICE]
Flush 5
Log_Level info
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
[OUTPUT]
Name loki
Url http://loki:3100/loki/api/v1/push
TenantID ""
Labels {job="fluent-bit"}
BatchWait 1
BatchSize 10240
LineFormat json
LogLevel info
Bu sayede ne oluyor?
Hatırlatma: IRP’yi CI/CD pipeline’ına ekleyin – her deploy sonrası smoke test çalıştırın. 🔁
Kolay gelsin, soruların olursa yanımda! 🚀
Aşağıda, önceki bölümlerde ele alınan temel yaklaşımları özetleyen bir karşılaştırma tablosu bulunmaktadır. Güvenlik, Performans, Maliyet, Karmaşıklık ve Uyumluluk ile ilgili en önemli farklar burada.
| Kriter | Bulut Tabanlı Çözüm | İçeride Barındırılan Çözüm | Hibrit Çözüm |
|---|---|---|---|
| Güvenlik | Yetkilendirme ve izleme hizmetleri sağlar; özel donanım gemileri de mevcuttur. | Her şeyi kendiniz yönetirsiniz; kontrolleri tamamen size aittir. | Hem kontrol hem paylaşımla, en iyi güvenlik duruşunu seçebilirsiniz. |
| Performans | Yakın tehlike yönetimi ve uçtan uca sinyalleme; ancak günlük iş yükleri yüksek olabilir. | En düşük gecikme süresi; ancak ölçeklendirme kendinize aittir. | Sunucularınızı iş yüküne göre dağıtabilirsiniz; eşlemenin keyfine varacaksınız. |
| Maliyet | Pay-as-you-go fiyatlandırması; başlangıçta daha az sermayeye ihtiyacınız olur. | Donanım, lisans ve işletme masrafları için yüksek sermaye yatırımı gerekir. | Zamanla güncelleme yapın: Bulut özelliklerini hızla benimseme veya kendi merkezinizde tutma. |
| Karmaşıklık | En basit yaklaşım; platformu kullanan insanlar bunun üstesinden gelir. | Operasyonlar, çaptan, işletmeden ve yasal gerekliliklerden anlayan deneyimli ekip gerektirir. | En yüksek düzeyde karmaşıklığa sahiptir; iyi entegre edilmiş bir işlem süreci gerekir. |
| Uyumluluk | Sürücüleri otomatik olarak günceller ve çoğu endüstri standardı uyumluluk komutlarını sunar. | Uyumluluk tamamen size bağlı; belgelere ihtiyaç duyarsınız. | Uyumluluğu tercih ettiğiniz konuma göre yapılandırabilir ve diğer konumlarda özel talepleri karşılayabilirsiniz. |
Veri kim tarafından kontrol edilmeli?
Sunucu güvenilir mi?
Bütçe limiti nedir?
Uygulamanız esnek mi ve yeni özellikleri hızla alabilir mi?
Özel donanım/SDK gereksinimi var mı?
Ekipleriniz yeni teknolojileri yönetebilecek yetkinlikte mi?
Sunucu güvenilir mi?
├─ Evet → Veriye kim sahip olmalı?
│ ├─ Müşteri → İçeride Barındırılan
│ └─ Sağlayıcı → Bulut Tabanlı
└─ Hayır → Güvenlik ve uyumluluk için Hibrit ile başlayın
Bu akışı kendi yetkinlikleriniz, uyumluluk ihtiyaçlarınız ve bütçe sınırlarınız doğrultusunda değiştirin. Sadece güvenilir, hızlı ve etkili bir çözüme ihtiyacınız olduğunda karar verin.
Sonuç olarak: Tabloyu değerlendirerek ve soruları yanıtlayarak (veya akışı ilerleterek), ortamınıza en uygun yaklaşımı seçebilirsiniz. Hadi, doğru seçime ulaşalım! 🚀
Hazırsan理论的 konuları biraz boşlukta bırakıp, tarayıcıda çalışan tam bir örnek yazalım 🚀
Web Crypto API kullanarak: anahtar üretme → IV oluşturma → şifreleme → Base64 encode → çözme adımlarını tek bir HTML dosyasında toplayacağız.
Kopyala, index.html olarak kaydet, tarayıcıda aç — işte bu kadar basit.
try/catch) ile kullanıcıya anlamlı mesaj ver<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>Client-Side AES-GCM Demo</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 720px; margin: 2rem auto; padding: 0 1rem; }
textarea, input, select { width: 100%; font-family: monospace; padding: 0.5rem; margin: 0.5rem 0; box-sizing: border-box; }
button { padding: 0.6rem 1.2rem; margin-right: 0.5rem; cursor: pointer; }
.output { background: #f5f5f5; border: 1px solid #ddd; padding: 1rem; white-space: pre-wrap; word-break: break-all; min-height: 60px; }
.error { color: #c00; background: #ffecec; padding: 0.5rem; border-radius: 4px; display: none; }
.success { color: #080; display: none; }
</style>
</head>
<body>
<h1>🔐 AES-GCM Şifreleme / Çözme Demo</h1>
<p><strong>Not:</strong> Bu sayfa tamamen client-side çalışır. Veri sunucuya gitmez.</p>
<!-- Anahtar girişi -->
<label>
<strong>Anahtar (Base64, 256-bit = 44 karakter):</strong><br>
<input type="text" id="keyInput" placeholder="Boş bırakırsan rastgele üretilir" spellcheck="false">
<button type="button" id="genKeyBtn">🎲 Rastgele Anahtar Üret</button>
</label>
<!-- Metin girişi -->
<label>
<strong>Açık Metin:</strong><br>
<textarea id="plainInput" rows="4" placeholder="Şifrelenecek metni buraya yaz..."></textarea>
</label>
<!-- Butonlar -->
<button id="encryptBtn">🔒 Şifrele</button>
<button id="decryptBtn">🔓 Çöz</button>
<button id="clearBtn" style="background:#eee;">🧹 Temizle</button>
<!-- Hata / başarı mesajları -->
<div id="errBox" class="error"></div>
<div id="okBox" class="success"></div>
<!-- Çıktı -->
<label>
<strong>Sonuç (Base64):</strong><br>
<div id="output" class="output"></div>
</label>
<hr>
<details>
<summary>🛡 Güvenlik Notları (tıklayıp oku)</summary>
<ul>
<li><strong>IV asla yeniden kullanma!</strong> Her şifrelemede <code>crypto.getRandomValues()</code> ile yeni IV üretiyoruz. Aynı anahtar + IV kombinasyonu iki kez kullanılırsa güvenlik kırılır ❌</li>
<li><strong>Anahtarı nasıl saklarsın?</strong> Bu demo'da anahtar input'ta duruyor. Gerçek uygulamalarda: <code>crypto.subtle.exportKey("jwk", key)</code> ile dışa aktarıp <strong>Password-Based Key Derivation (PBKDF2)</strong> ile kullanıcı şifresinden türet, veya <strong>Web Crypto Key Storage</strong> (extractable: false) kullan.</li>
<li><strong>HTTPS zorunlu!</strong> Web Crypto API <code>secure context</code> (localhost veya HTTPS) gerektirir.</li>
<li><strong>Auth tag</strong> AES-GCM'de şifreli metin içine gömülüdür (son 16 byte). Çözme sırasında ayrı yönetmen gerekmez.</li>
</ul>
</details>
<script>
/* ===== Yardımcı: Uint8Array ↔ Base64 ===== */
const u8ToB64 = (u8) => btoa(String.fromCharCode(...u8));
const b64ToU8 = (b64) => new Uint8Array(atob(b64).split('').map(c => c.charCodeAt(0)));
/* ===== Hata / başarı göster ===== */
const errBox = document.getElementById('errBox');
const okBox = document.getElementById('okBox');
const setErr = (msg) => { errBox.textContent = msg; errBox.style.display = 'block'; okBox.style.display = 'none'; };
const setOk = (msg) => { okBox.textContent = msg; okBox.style.display = 'block'; errBox.style.display = 'none'; };
/* ===== Anahtar üret / input'a yaz ===== */
document.getElementById('genKeyBtn').onclick = async () => {
try {
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true, // extractable: true → demo için dışa aktarılabilir
['encrypt', 'decrypt']
);
const raw = await crypto.subtle.exportKey('raw', key);
document.getElementById('keyInput').value = u8ToB64(new Uint8Array(raw));
setOk('✅ Yeni 256-bit anahtar üretildi.');
} catch (e) { setErr('Anahtar üretilemedi: ' + e.message); }
};
/* ===== Input'tan anahtarı içe aktar ===== */
async function importKeyFromInput() {
const b64 = document.getElementById('keyInput').value.trim();
if (!b64) throw new Error('Anahtar boş! Önce "Rastgele Anahtar Üret" butonuna bas.');
const raw = b64ToU8(b64);
if (raw.length !== 32) throw new Error('Anahtar 32 byte (256-bit) olmalı, şu an: ' + raw.length + ' byte');
return crypto.subtle.importKey('raw', raw, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);
}
/* ===== Şifrele ===== */
document.getElementById('encryptBtn').onclick = async () => {
try {
const key = await importKeyFromInput();
const plain = document.getElementById('plainInput').value;
if (!plain) throw new Error('Şifrelenecek metin boş.');
// 1️⃣ IV üret (96-bit = 12 byte — GCM için önerilen boyut)
const iv = crypto.getRandomValues(new Uint8Array(12));
// 2️⃣ Şifrele (Web Crypto API: alg + iv + data)
const enc = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
new TextEncoder().encode(plain)
);
// 3️⃣ IV + ciphertext birleştir → Base64
// Format: [IV (12 byte)][Ciphertext + AuthTag]
const combined = new Uint8Array(iv.length + enc.byteLength);
combined.set(iv, 0);
combined.set(new Uint8Array(enc), iv.length);
document.getElementById('output').textContent = u8ToB64(combined);
setOk('✅ Şifrelendi. IV (ilk 12 byte) + ciphertext Base64 olarak yukarıda.');
} catch (e) { setErr('Şifreleme hatası: ' + e.message); }
};
/* ===== Çöz ===== */
document.getElementById('decryptBtn').onclick = async () => {
try {
const key = await importKeyFromInput();
const b64 = document.getElementById('output').textContent.trim();
if (!b64) throw new Error('Çözülecek veri yok. Önce şifrele.');
const combined = b64ToU8(b64);
if (combined.length < 13) throw new Error('Veri çok kısa, IV (12 byte) + en az 1 byte ciphertext gerekli.');
// 1️⃣ IV'yi ayıkla (ilk 12 byte)
const iv = combined.slice(0, 12);
const ciphertext = combined.slice(12); // geri kalanı (ciphertext + auth tag)
// 2️⃣ Çöz
const dec = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
ciphertext
);
document.getElementById('plainInput').value = new TextDecoder().decode(dec);
setOk('✅ Çözüldü! Açık metin yukarıdaki kutuda.');
} catch (e) {
// Yaygın hata: yanlış anahtar / bozulmuş veri / yanlış IV
setErr('Çözme hatası: ' + e.message + ' — Anahtar/IV uyuşmuyor ya da veri bozulmuş olabilir.');
}
};
/* ===== Temizle ===== */
document.getElementById('clearBtn').onclick = () => {
document.getElementById('plainInput').value = '';
document.getElementById('output').textContent = '';
errBox.style.display = 'none';
okBox.style.display = 'none';
};
</script>
</body>
</html>
| Adım | Ne oluyor? |
|---|---|
| 1. Anahtar | generateKey → 256-bit AES-GCM anahtarı → exportKey('raw') → Base64'e çevir → input'a yaz |
| 2. IV | crypto.getRandomValues(new Uint8Array(12)) → her şifrelemede benzersiz 🎯 |
| 3. Şifrele | crypto.subtle.encrypt({name:'AES-GCM', iv}, key, data) → auth tag otomatik eklenir |
| 4. Birleştir | IV (12 byte) + ciphertext+tag → tek Uint8Array → Base64 |
| 5. Çöz | Base64 → Uint8Array → ilk 12 byte = IV, geri kalan = ciphertext → decrypt() |
Anahtarı kopyalayıp başka bir sekmede aynı sayfayı açıp yapıştırırsan → yine çözersün (IV her seferinde farklı olsa da anahtar aynıysa çözme çalışır).
IV yeniden kullanma = felaket ❌
Bu demo'dacrypto.getRandomValues()ile rastgele IV üretiyoruz — bu kriptografik olarak güvenli rastgelelik sağlar.
Eğer sayaç (counter) tabanlı IV kullanacaksan (örn. mesaj numarası), o zaman stateful olman ve asla tekrar etmemen gerekir.
Anahtarı ise: production'daextractable: falseileCryptoKeyobjesi olarak tut, veya PBKDF2/Argon2 ile kullanıcı şifresinden türet. Asla localStorage'a Base64 anahtar yazma 🙅♂️
Hadi şimdi dene, kır, değiştir — en iyi öğrenme yolu bu 😉
Hadi şimdi, konuştuğumuz her şeyi bir kez daha özetleyip yola çıkalım 🚀
Doğru şifreleme stratejisi, veri güvenliğinizin kalbidir. Bu cümle sadece bir slogan değil — günlük işimizde en çok başımızı ağrıtan, ama en çok da ihmal ettiğimiz nokta. Küçük bir hatırlatma listesiyle bitirelim:
Her iki belge de masa başınızda olmalı — arama yapmak yerine doğrudan linkleri kaydedin. ⭐
Bu yazıdaki bir stratejiyi uyguladınız mı? Ya da "Bu algoritmayı denedim, şu sorunu yaşadım" diye bir hikayeniz var mı? Yorumlarda paylaşın — birbirimizden öğrenmek, tek başımıza doküman okumaktan çok daha hızlı (ve eğlenceli) olur. 😊
Mutlu kodlamalar! 🎉
Güvenli, temiz ve uyumlu bir kod tabanıyla yolunuz açık olsun. Bir sonraki yazıda görüşmek üzere… 👋
Bu içerik tamamen yapay zeka destekli otomasyon sistemi ile üretilmiştir.
All rights reserved