Gereksinimler ve Ön Hazırlık
İleri düzey bir şifreleme sistemi kurmak için Flutter projenizde bazı bağımlılıklara ve güvenli donanım erişimlerine ihtiyacınız vardır. 2026 yılı itibarıyla en güncel ve güvenli kütüphaneleri kullanarak projemizi yapılandıracağız.
- Flutter SDK: 3.24 veya üzeri sürüm.
- encrypt: Dart için yüksek seviyeli şifreleme kütüphanesi.
- flutter_secure_storage: Anahtarları cihazın güvenli donanımında (iOS Keychain, Android Keystore) saklamak için.
- pointycastle: Şifreleme algoritmalarının düşük seviyeli uygulamaları için.
Projenizin pubspec.yaml dosyasına şu bağımlılıkları ekleyerek işe başlayın:
dependencies:
flutter:
sdk: flutter
encrypt: ^5.0.3
flutter_secure_storage: ^9.2.2
Adım 1: Güvenli Anahtar Yönetimi ve Üretimi
Şifreleme sisteminin en zayıf halkası, kullanılan anahtarların saklanma biçimidir. Anahtarı sabit kod (hard-coded) olarak yazmak, uygulamanın tersine mühendislik ile kolayca kırılmasına neden olur. Bunun yerine, anahtarı cihazın işletim sistemi düzeyindeki güvenli alanında oluşturup saklamalıyız.
Aşağıdaki kod bloğu, uygulama ilk kez çalıştığında güvenli bir AES anahtarı oluşturur ve bunu cihazın güvenli deposunda saklar:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:encrypt/encrypt.dart';
import 'dart:convert';
class KeyManager {
final _storage = const FlutterSecureStorage();
Future getEncryptionKey() async {
String? keyString = await _storage.read(key: 'encryption_key');
if (keyString == null) {
final key = Key.fromSecureRandom(32); // 256-bit anahtar
await _storage.write(key: 'encryption_key', value: base64Url.encode(key.bytes));
return key;
}
return Key.fromBase64(keyString);
}
}
Bu kod, anahtarın cihazda kalıcı olmasını sağlar. Uygulama silinmediği sürece aynı anahtar kullanılır, böylece verilerin şifresini çözmek mümkün olur.
Adım 2: AES Algoritması ile Veri Şifreleme
AES (Gelişmiş Şifreleme Standardı), veriyi bloklar halinde işleyen ve dünya genelinde kabul görmüş en güvenli simetrik şifreleme yöntemidir. Flutter'da encrypt paketi ile CBC (Cipher Block Chaining) modunu kullanarak veriyi şifreleyeceğiz.
class EncryptionService {
final Key key;
final IV iv = IV.fromLength(16); // Rastgele başlatma vektörü
EncryptionService(this.key);
String encryptData(String plainText) {
final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
final encrypted = encrypter.encrypt(plainText, iv: iv);
return encrypted.base64;
}
}
Burada IV (Initialization Vector), aynı verinin her seferinde farklı bir şifreli metin üretmesini sağlar. Bu, saldırganların aynı veriler arasındaki örüntüleri bulmasını engeller.
Adım 3: Şifrelenmiş Verinin Çözülmesi
Şifrelediğimiz veriyi geri okumak için aynı anahtarı ve aynı IV değerini kullanmamız gerekir. İleri düzey uygulamalarda, IV değerini verinin başına ekleyerek saklamak yaygın bir pratiktir.
String decryptData(String encryptedBase64) {
final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
final encrypted = Encrypted.fromBase64(encryptedBase64);
return encrypter.decrypt(encrypted, iv: iv);
}
Bu fonksiyon, şifreli metni alır ve orijinal haline döndürür. Eğer anahtar veya IV eşleşmezse, sistem bir hata fırlatacaktır; bu da şifreleme bütünlüğünü korur.
Adım 4: Yerel Veritabanı (SQLite) ile Entegrasyon
Verileri şifreledikten sonra, bunları yerel bir veritabanında (örneğin sqflite) saklamak isteyebilirsiniz. Veritabanı dosyasına doğrudan erişilse bile, içindeki veriler anlamsız karakter dizileri olarak görünecektir.
Future saveEncryptedUserNote(String note) async {
final key = await KeyManager().getEncryptionKey();
final service = EncryptionService(key);
final encryptedNote = service.encryptData(note);
// Veritabanı insert işlemi burada yapılır
// db.insert('notes', {'content': encryptedNote});
}
Bu yöntemle, veritabanı dosyanız çalınsa veya cihaz root edilse bile, verilerin şifresini çözmek için gereken anahtar güvenli depolama alanında (sandbox) korunduğu için veriler okunamaz kalır.
Karşılaştırma Tablosu: Şifreleme Yöntemleri
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| AES-CBC | Hızlı ve yaygın destek | IV yönetimi gerektirir |
| RSA (Asimetrik) | Anahtar paylaşımı güvenli | Çok yavaş, büyük veriler için uygun değil |
| Hashing (SHA-256) | Tek yönlü, geri döndürülemez | Veri kurtarılamaz (sadece doğrulama) |
Adım 5: Güvenlik Uyarıları ve En İyi Pratikler
Kritik Uyarı: Şifreleme anahtarlarını asla uygulama kodunun içine gömmeyin. Üretim ortamında (production), anahtarın cihazın güvenli donanımında saklandığından emin olun. Ayrıca, şifrelenmiş verileri yedeklerken (Cloud Backup), yedekleme ayarlarında bu verilerin şifreli kalmasını sağlayan yapılandırmaları kontrol edin.
Uygulamanızda şifreleme kullanırken dikkat etmeniz gereken diğer hususlar şunlardır:
- Bellek Yönetimi: Çok büyük verileri şifrelerken belleği (RAM) tüketmemeye dikkat edin, veriyi parçalar halinde işleyin.
- Hata Yönetimi: Şifre çözme sırasında oluşan hataları (örneğin yanlış anahtar) kullanıcıya "Veri bozuk" gibi genel bir mesajla bildirin; teknik detayları loglamayın.
- Obfuscation: Flutter'ın sunduğu
--obfuscatekomutunu kullanarak kodunuzu karıştırın.
Sıkça Sorulan Sorular
Şifreleme anahtarımı kaybedersem ne olur?
Eğer anahtarı kaybederseniz, şifrelenmiş verileri geri döndürmeniz imkansızdır. Bu nedenle, anahtar yönetimi stratejinizi oluştururken anahtarın cihazda kalıcı olduğundan ve uygulama güncellemelerinde silinmediğinden emin olun.
AES-CBC yerine neden AES-GCM kullanmıyoruz?
AES-GCM, hem şifreleme hem de doğrulama (authentication) sağlar. Eğer verinizin değiştirilip değiştirilmediğini de kontrol etmek istiyorsanız, 2026 standartlarında AES-GCM kullanmanız daha güvenli bir tercih olacaktır.
Flutter Web üzerinde de çalışır mı?
Evet, ancak flutter_secure_storage web üzerinde farklı davranır. Web için IndexedDB veya localStorage üzerinde şifreleme yaparken tarayıcı güvenliği kısıtlamalarını göz önünde bulundurmalısınız.
Uygulamayı silip tekrar yüklersem verilerim ne olur?
Güvenli depolama alanı uygulama ile birlikte silinir. Eğer anahtarı yedeklemediyseniz (ki bu güvenlik riski oluşturur), şifreli verileriniz erişilemez hale gelir.
Bu sistem SQL Injection saldırılarını önler mi?
Şifreleme, verinin içeriğini korur; ancak SQL Injection'ı doğrudan engellemez. SQL Injection için her zaman parametreli sorgular (prepared statements) kullanmalısınız.
Performans Optimizasyonu ve Büyük Veri Setlerinde Şifreleme
Mobil uygulamalarda şifreleme işlemleri, özellikle büyük veri setleri üzerinde çalışırken işlemci (CPU) üzerinde ciddi bir yük oluşturabilir. AES-256 gibi güçlü algoritmalar, ana belleği ve işlemciyi yoğun bir şekilde kullanır. Performansı optimize etmek için şifreleme işlemlerini ana UI (User Interface) thread'inden ayırmanız kritik öneme sahiptir.
Isolate Kullanarak Şifreleme İşlemlerini Arka Plana Taşıma
Flutter'da ağır hesaplamaları compute fonksiyonu veya doğrudan Isolate kullanarak ayrı bir thread'de çalıştırmak, uygulamanın donmasını (jank) engeller. Aşağıdaki örnek, büyük bir metin bloğunu arka planda şifrelemek için compute kullanımını göstermektedir:
import 'package:flutter/foundation.dart';
import 'package:encrypt/encrypt.dart';
// Şifreleme işlemini ayrı bir fonksiyona taşıyoruz
String encryptDataInIsolate(Map data) {
final key = Key.fromBase64(data['key']);
final iv = IV.fromBase64(data['iv']);
final encrypter = Encrypter(AES(key));
return encrypter.encrypt(data['plainText'], iv: iv).base64;
}
// Kullanım örneği
Future performSecureEncryption(String plainText, String key, String iv) async {
return await compute(encryptDataInIsolate, {
'plainText': plainText,
'key': key,
'iv': iv,
});
}
Şifreleme Sistemlerinde Hata Ayıklama ve Log Yönetimi
Güvenlik odaklı uygulamalarda hata ayıklama (debugging) süreci, güvenlik açıklarına yol açabilecek en riskli alanlardan biridir. Hata mesajlarında şifrelenmiş veriyi veya anahtar parçalarını asla loglamamalısınız. Bunun yerine, işlemin başarılı olup olmadığına dair soyut hata kodları kullanın.
Güvenli Hata Yönetimi Stratejisi
- Hassas Veri Maskeleme: Log çıktılarınızda şifrelenmiş verinin sadece ilk veya son 4 karakterini gösterin.
- Exception Handling: Şifreleme başarısız olduğunda kullanıcıya "Veri işlenemedi" gibi genel bir hata mesajı dönün; teknik detayları (örneğin: "Invalid Key Length") sadece uygulama içi güvenli log dosyalarına kaydedin.
- Production Kontrolü:
kReleaseModedeğişkenini kullanarak, uygulama yayına alındığında tüm debug loglarını devre dışı bırakın.
try {
// Şifreleme denemesi
} catch (e) {
if (kReleaseMode) {
// Sadece hata türünü logla, içeriği asla kaydetme
Logger.log("Encryption Error: CODE_001");
} else {
// Geliştirme aşamasında detaylı hata
print("Detaylı Hata: $e");
}
}
İleri İpucu: Bellek Güvenliği (Memory Safety)
Dart'ın çöp toplayıcı (Garbage Collector) mekanizması, değişkenlerin bellekten ne zaman silineceği konusunda kesin bir garanti vermez. Çok hassas veriler (örneğin özel anahtarlar) için, işlem biter bitmez değişkeni null değerine eşitleyerek referansı koparmak, bellekteki hassas verinin ömrünü kısaltmak adına iyi bir pratik olarak kabul edilir.
Sonuç
Flutter ile ileri düzey bir şifreleme sistemi kurmak, verilerinizin güvenliğini sağlamak adına atabileceğiniz en önemli adımdır. AES şifreleme, güvenli anahtar yönetimi ve doğru kütüphane kullanımı ile mobil uygulamanızı siber saldırılara karşı çok daha dirençli hale getirebilirsiniz. Bir sonraki adım olarak, anahtarların periyodik olarak değiştirilmesi (Key Rotation) mekanizmasını araştırmanızı öneririm.
Yasal Sorumluluk Reddi: Bu makalede paylaşılan kodlar eğitim amaçlıdır. Uygulamanızın güvenlik mimarisini kurarken, uygulamanın çalıştığı sektörün (finans, sağlık vb.) gerektirdiği yasal uyumluluk standartlarını (KVKK, GDPR) mutlaka bir siber güvenlik uzmanına danışarak doğrulayın.


Yorumlar (0)
Yorum Yaz