Flutter Api ve Key Güvenliği
Merhaba değerli okurlar.
Flutter ile göz alıcı, hızlı ve platformlar arası uygulamalar geliştirmek kolay ve güzel. Ancak bu şık arayüzlerin arkasında, uygulamanızın dış dünyayla konuştuğu kritik bir altyapı yatıyor: API’lar. Hava durumu servisleri, haritalar, ödeme ağ geçitleri, kendi backend servisleriniz… Hepsi API’lar aracılığıyla iletişim kurar ve bu iletişimin anahtarı genellikle API anahtarlarıdır.
Peki, bu değerli dijital anahtarları nerede saklıyorsunuz? Eğer cevabınız “Doğrudan Flutter kodunun içinde, bir değişkende (String apiKey = ‘…’)” ise, farkında olmadan uygulamanızın güvenliğini riske atıyor olabilirsiniz. Bu makalede, Flutter API ve anahtar güvenliğinin neden bu kadar kritik olduğunu anlayacak, yaygın hatalardan kaçınacak ve adım adım daha güvenli, hatta profesyonel seviyede çözümler inşa edeceğiz. Yolculuğumuz, en güvensiz yöntemden başlayıp, güvenli bir PHP Backend for Frontend (BFF) katmanı oluşturmaya ve hatta bu BFF katmanını da koruma altına almaya kadar uzanacak. Fakat öncesinde neden bu anahtarların koda gömülmemesi üzerine konuşacağız.
Neden API Anahtarlarını Koda Göm(e)memelisiniz?
- Tersine Mühendislik (Reverse Engineering): Yayınladığınız APK veya IPA dosyaları, kötü niyetli kişiler tarafından decompile edilebilir (kaynak koduna yakın bir hale getirilebilir). Kod içindeki metin halindeki API anahtarları, bu inceleme sırasında kolayca bulunabilir.
- Kötüye Kullanım ve Maliyet: Ele geçirilen bir anahtar felakete yol açabilir:
- Ücretli API’lerde Yüksek Faturalar: Anahtarınızı kullanan biri, sizin adınıza servisi aşırı kullanarak size yüklü faturalar çıkarabilir.
- Kota Aşımı: Ücretsiz veya limitli API kotalarınız hızla tükenebilir, uygulamanız çalışmaz hale gelebilir.
- Veri İhlalleri: Anahtar, hassas verilere erişim sağlıyorsa, yetkisiz kişiler bu verilere ulaşabilir.
3. Versiyon Kontrolü Riskleri: Anahtarları içeren kodu yanlışlıkla herkese açık bir Git deposuna göndermek, anahtarınızın anında ifşa olması demektir. .gitignore dosyaları unutulabilir veya yanlış yapılandırılabilir.
4. Güvensiz İletişim (HTTP): Eğer API isteklerinizi şifrelenmemiş http:// üzerinden yapıyorsanız, ağ trafiğini dinleyen biri anahtarlarınızı ve verilerinizi kolayca ele geçirebilir. Her zaman https:// kullanın!
Artık neden koda bu keyleri gömmemimiz gerektiğini daha iyi anladığımızı düşünüyorum. Şimdi sıra geldi ilgili yapımızla tanışmaya.
Bu yöntem benim kendi API’larımı yazarken kullandığım bir yöntemdir. Umuyorumki sizler içinde hem faydalı olacaktır hemde daha iyisini yapabilmek için bir ışık yakacaktır sizde..
BFF Modeli ile Tanışma
API anahtarlarını Flutter kodundan uzaklaştırmanın en etkili yollarından biri Backend for Frontend (BFF) modelidir.
- BFF Nedir? BFF, sadece sizin Flutter uygulamanızın ihtiyaçlarına hizmet etmek üzere tasarlanmış, sizin kontrolünüzdeki bir ara katman sunucusudur. Bu sunucuyu bu yazımda PHP ile kodluyor olacağız.
Nasıl Çalışır?
- Hassas Anahtar BFF’de: Asıl API anahtarı (örn. OpenWeatherMap) sadece BFF sunucusunda, güvenli bir yerde saklanır.
- Flutter BFF’e İstek Yapar: Flutter uygulaması, hava durumu verisi istediğinde, OpenWeatherMap’e değil, kendi BFF sunucusuna (API anahtarını göndermeden) istek yapar.
- BFF İşi Halleder: BFF, isteği alır, güvenli yerden anahtarı okur ve OpenWeatherMap’e kendi adına isteği yapar.
- Yanıt Geri Döner: BFF, OpenWeatherMap’ten gelen yanıtı alır ve Flutter uygulamasına iletir.
Uygulamalı BFF İnşası (PHP ile)
Şimdi OpenWeatherMap API’sini kullanarak basit ama güvenli bir PHP BFF’i oluşturalım.
Ben bu örnekte kendi sunucumu kullanarak bu yapıyı oluşturuyor olacağım. Dileyen localhost üzerindende benzer yapı oluşturup test edebilir. Gerçek bir sunucu üzerinden ve OpenWeatherMap API’sini kullanarak anlatım yaptığımı tekrar vurgulamış olayım!
1. Öncelikle sunucumuzun ana dizininde (home/kullanıcıadınız) config adlı bir klasör oluşturalım. Daha sonra bu klasör içine config.php adlı bir dosya oluşturalım. Yapımız aşağıdaki gibi olmalı
/home/kullaniciadiniz/
├── config/ ← Web Kökü DIŞINDA (Gizli Alan)
│ └── config.php ← API Anahtarlarımız burada
└── public_html/ ← Web Kökü (Erişilebilir Alan)
2. Oluşturduğumuz config.php dosyasını düzenleyerek içine OpenWeatherMap API’den aldığımız keyi yazıyoruz. Dosyanın son hali aşağıdaki gibi olacaktır. SİZİN_OPENWEATHERMAP_API_ANAHTARINIZ yerine OPENWEATHERMAP API keyinizi yazmanız gerekiyor. Ayrıca bu dosyanın izinlerine de dikkat etmeniz gerekiyor.
Birde uygulamanızı ve backend tarafını daha güçlü hale getirmek için istek atılacak backend dosyamız için oluşturacağımız güçlü bir şifre ekliyoruz. Böylece endpointlerimiz bilinse bile bu şifre olmadan response alınamayacaktır.
<?php
// /home/kullaniciadiniz/config/config.php
define(‘OPENWEATHERMAP_API_KEY’, ‘SİZİN_OPENWEATHERMAP_API_ANAHTARINIZ’);
define('FLUTTER_APP_BFF_KEY', 'GucluTahminEdilemezBirParola');
?>
3. Şimdi sıra geldi bu api keyi kullanarak bize girdiğimiz değere göre hava durumunu getiren ilgili yapıyı kurmaya. Ben weather_bff.php olarak adlandırıyorum dosyayı sizler istediğiniz gibi adlandırabilirsiniz. Fakat dosyanın oluşturulacağı alanın public_html altında olduğuna dikkat edin
/home/kullaniciadiniz/
├── config/ ← Web Kökü DIŞINDA (Gizli Alan)
│ └── config.php ← API Anahtarlarımız burada
└── public_html/ ← Web Kökü (Erişilebilir Alan)
└── weather_bff.php ← Flutter’ın konuşacağı dosya
Aşağıdaki kodları kopyalayıp kendi php dosyanıza yapıştırabilirsiniz. Satır aralarında kodların ne işe yaradığını açıkladık.
Bu adımdan sonra artık Flutter tarafına geçip yapımızı test edebiliriz. Tüm kodları doğrudan main.dart dosyasına yapıştırarak test edebilirsiniz.
Uygulamayı çalıştırmaya geçmeden önce 2 önemli noktayı açıklamaya çalışacağım.
String.fromEnvironment
const String bffAppKey = String.fromEnvironment(
‘BFF_APP_KEY’,
defaultValue: ‘’,
);
- Ne İşe Yarıyor? Burası güvenliğin Flutter tarafındaki kilit noktalarından biri. Bu kod, uygulamayı derlerken veya çalıştırırken komut satırından ( — dart-define=BFF_APP_KEY=”DEĞER”) bize verilen BFF_APP_KEY adlı “gizli notu” okur.
- Neden Önemli? BFF’e erişim için gereken uygulama anahtarını doğrudan koda yazmıyoruz! Koda yazarsak, tersine mühendislikle bulunabilirdi. String.fromEnvironment sayesinde anahtar, derleme anında dışarıdan enjekte edilir ve kodun içinde statik bir metin olarak yer almaz. Bu, güvenliği önemli ölçüde artırır.
- defaultValue: ‘’: Eğer — dart-define ile anahtar verilmezse, bffAppKey boş bir string olur.
_getWeatherFromBff Fonksiyonu
- Fonksiyon, önce gerekli kontrolleri yapar (anahtar var mı, şehir girilmiş mi).
- Sonra http.get ile isteği yapar ANCAK bu sefer headers parametresini kullanır.
- headers içine, PHP tarafında kontrol ettiğimiz ‘X-App-Key’ başlığını ve değer olarak da String.fromEnvironment ile okuduğumuz bffAppKey’i ekler.
- PHP tarafı bu başlığı ve anahtarı kontrol eder. Doğruysa, isteği işler; değilse 401/403 hatası döndürür.
- Flutter tarafı da gelen yanıta göre (200, 401, 403 veya diğerleri) sonucu veya hata mesajını ekrana yansıtır.
Şimdi uygulamamızı çalıştırıp, bu yapının nasıl çalıştığını gözlemleyebilirsiniz. Fakat direkt run & debug diyerek çalıştırırsanız alacağınız hata bu olacaktır;
UYARI: BFF_APP_KEY derleme zamanında sağlanmadı! İstekler başarısız olabilir.
Peki nasıl çalıştıracağız uygulamayı?
--dart-define
Yukarıdaki metot ile.. — dart-define, Flutter uygulamanızı derlerken veya çalıştırırken komut satırı üzerinden uygulamanızın Dart koduna ortam değişkenleri (environment variables) veya yapılandırma değerleri göndermenizi sağlayan bir komut satırı argümanıdır.
Basitçe söylemek gerekirse, kodunuzun dışından, derleme/çalıştırma anında kodunuza bilgi (“tanım” — definition) aktarmanıza olanak tanır.
Bizde uygulamamızı çalıştırırken bu komuttan faydalanıp terminale aşağıdaki gibi bir kod yazıp uygulamayı çalıştıracağız;
flutter run --dart-define=BFF_APP_KEY=”GucluTahminEdilemezBirParola123”
GucluTahminEdilemezBirParola123 yerine config.php dosyanızda belirlediğiniz parolanızı girebilirsiniz.
Diğer kullanımlar burada;
flutter build apk \
— release \
— dart-define=API_KEY=”PROD_abc123xyz_VERY_SECRET”
flutter build appbundle \
— release \
— dart-define=API_KEY=”PROD_abc123xyz_VERY_SECRET”
flutter build ios \
— release \
— dart-define=API_KEY=”PROD_abc123xyz_VERY_SECRET”
build veya appbundle almak için yukarıdaki kodlardan yararlanabilirsiniz. Ek bilgi olarak birden fazla define komutu kullanabilirsiniz belirtmiş olayım.
Toparlayacak olursak;
Yöntem %100 olarak güçlü bir yapı olmasada tersine mühendislik yapıldığında aşılması güç duvarlar oluşturacaktır. Yine bu katmanları güçlendirmek için obfuscate ve split-debug-info kullanabilirsiniz.
Çok kısa olarak değinmeye çalışalım bu komutlarada;
- — obfuscate: Uygulamanızın derlenmiş kodunun çıktısını değiştirir. Dart kodundaki sembolleri (sınıf, metot, değişken adları) yeniden adlandırarak okunmasını ve tersine mühendisliğini zorlaştırır.
- — split-debug-info: Yine derlenmiş çıktıyı etkiler. Kod gizleme ile birlikte kullanılan hata ayıklama sembollerini ayrı dosyalara çıkararak uygulama boyutunu küçültür ve bu sembolleri güvenli bir yerde saklamanıza olanak tanır (çökme raporlarını anlamlandırmak için gereklidir).
flutter build appbundle \
— release \
— obfuscate \
— split-debug-info=build/app/outputs/symbols \
— dart-define=API_KEY=”PROD_VERY_SECRET_KEY_123" \
— dart-define=BASE_URL=”https://api.myprodserver.com" \
— dart-define=IS_PRODUCTION=true
Bu yazımda sizlere Flutter API ve Key güvenliği konusunda bilgilendirici içerikler sunmaya çalıştım. Tersine mühendislik konusunda kodlarımızı nasıl daha korunaklı hale getirebileceğimizi anlatmaya çalıştım. Umarım sizler için açıklayıcı ve aydınlatıcı bir yazı olmuştur..
Github: www.github.com/abdullah017
Linkedin: www.linkedin.com/in/abdullahtas
Stackoverflow: https://stackoverflow.com/users/13807726/abdullah-t