OWASP kategorisi: MASVS-STORAGE: Depolama alanı
Genel Bakış
Günlük Bilgisi Yayınlama, uygulamaların hassas verileri cihaz günlüğüne yazdırdığı bir tür güvenlik açığıdır. Kötü amaçlı kişilere maruz kalan bu hassas bilgiler (ör. kullanıcı kimlik bilgileri veya kimliği tanımlayabilecek bilgiler (PII)) doğrudan değerli olabilir veya daha fazla saldırıya neden olabilir.
Bu sorun aşağıdaki senaryolardan herhangi birinde ortaya çıkabilir:
- Uygulama tarafından oluşturulan günlükler:
- Günlükler, yetkisiz aktörlere kasıtlı olarak erişim izni verir ancak yanlışlıkla hassas veriler içerir.
- Günlükler kasıtlı olarak hassas veriler içerir ancak yetkisiz kullanıcılar bu günlüklere yanlışlıkla erişebilir.
- Tetiklenen hata mesajına bağlı olarak bazen hassas verileri yazdırabilecek genel hata günlükleri.
- Harici olarak oluşturulan günlükler:
- Hassas veriler içeren günlüklerin yazdırılmasından harici bileşenler sorumludur.
Android Log.*
ifadeleri, ortak bellek arabelleğine logcat
yazar. Android 4.1'den (API düzeyi 16) itibaren, READ_LOGS
iznini beyan ederek yalnızca ayrıcalıklı sistem uygulamalarına logcat
okuma erişimi verilebilir. Ancak Android, önceden yüklenmiş uygulamalarında bazen READ_LOGS
ayrıcalığını açıklayan son derece çeşitli cihazlar destekler. Bu nedenle, veri sızıntısı riski daha yüksek olduğundan doğrudan logcat
'e günlük kaydı yapılması önerilmez.
logcat
adresine yapılan tüm günlük kayıtlarının, uygulamanızın hata ayıklama dışı sürümlerinde temizlendiğinden emin olun. Hassas olabilecek tüm verileri kaldırın. Ek bir önlem olarak, uyarı ve hata dışındaki tüm günlük düzeylerini kaldırmak için R8 gibi araçları kullanın. Daha ayrıntılı günlüklere ihtiyacınız varsa sistem günlüğünü kullanmak yerine dahili depolama alanını kullanın ve kendi günlüklerinizi doğrudan yönetin.
Etki
Günlük Bilgileri Açıklama güvenlik açığı sınıfının önem derecesi, bağlama ve hassas verilerin türüne bağlı olarak değişebilir. Genel olarak bu güvenlik açığı sınıfının etkisi, kimliği tanımlayabilecek bilgiler ve kimlik bilgileri gibi kritik olabilecek bilgilerin gizliliğinin kaybedilmesidir.
Çözümler
Genel
Tasarım ve uygulama sırasında genel bir önleyici tedbir olarak, güven sınırlarını en az ayrıcalık ilkesine göre çizin. İdeal olarak, hassas veriler güven alanlarının hiçbirini aşmamalı veya bu alanların dışına çıkmamalıdır. Bu, ayrıcalıkların ayrılmasını güçlendirir.
Hassas verileri günlüğe kaydetmeyin. Mümkün olduğunda yalnızca derleme zamanı sabitlerini günlüğe kaydedin. Derleme zamanında sabit not eklemek için ErrorProne aracını kullanabilirsiniz.
Tetiklenen hataya bağlı olarak hassas veriler de dahil olmak üzere beklenmedik bilgiler içerebilecek ifadeler yazdıran günlüklerden kaçının. Günlüklere ve hata günlüklerine yazdırılan veriler mümkün olduğunca yalnızca tahmin edilebilir bilgiler içermelidir.
logcat
'e günlük kaydetmekten kaçının. Bunun nedeni, READ_LOGS
iznine sahip uygulamalar nedeniyle logcat
'e giriş yapmanın gizlilik sorununa yol açabilmesidir. Ayrıca, uyarı tetikleyemediği veya sorgulanabildiği için etkisizdir. Uygulamaların logcat
arka ucunu yalnızca geliştirici derlemeleri için yapılandırmasını öneririz.
Çoğu günlük yönetimi kitaplığı, hata ayıklama ve üretim günlükleri arasında farklı miktarlarda bilginin günlüğe kaydedilmesine olanak tanıyan günlük düzeyleri tanımlamanıza olanak tanır. Ürün testi sona erdiğinde günlük düzeyini "debug" değerinden farklı olacak şekilde değiştirin.
Üretimden mümkün olduğunca fazla günlük düzeyini kaldırın. Günlükleri üretimde tutmaktan kaçınamıyorsanız sabit olmayan değişkenleri günlük ifadelerinden kaldırın. Aşağıdaki senaryolar gerçekleşebilir:
- Üretimdeki tüm günlükleri kaldırabilirsiniz.
- Üretimde Uyarı ve Hata günlüklerini tutmanız gerekir.
Bu iki durumda da R8 gibi kitaplıkları kullanarak günlükleri otomatik olarak kaldırın. Günlükleri manuel olarak kaldırma girişimleri hataya açıktır. Kod optimizasyonu kapsamında R8, hata ayıklama için tutmak istediğiniz günlük düzeylerini güvenli bir şekilde kaldıracak ancak üretimde kaldıracak şekilde ayarlanabilir.
Üretime giriş yapacaksanız bir olay durumunda günlük kaydını koşullu olarak kapatmak için kullanabileceğiniz işaretler hazırlayın. Olay yanıtı işaretleri şu konulara öncelik vermelidir: dağıtımın güvenliği; dağıtımın hızı ve kolaylığı, günlüklerin çıkartılmasının titizliği, bellek kullanımı ve her günlük mesajının taranmasının performans maliyetleri.
R8'i kullanarak üretim derlemelerindeki günlükleri logcat'e indirin.
Android Studio 3.4 veya Android Gradle eklentisi 3.4.0 ve sonraki sürümlerde kod optimizasyonu ve küçültme için varsayılan derleyici R8'dir. Ancak R8'i etkinleştirmeniz gerekir.
R8, ProGuard'ın yerini aldı ancak projenin kök klasöründeki kurallar dosyası hâlâ proguard-rules.pro
olarak adlandırılıyor.Aşağıdaki snippet'te, uyarılar ve hatalar hariç üretimdeki tüm günlükleri kaldıran örnek bir proguard-rules.pro
dosyası gösterilmektedir:
-assumenosideeffects class android.util.Log {
private static final String TAG = "MyTAG";
public static boolean isLoggable(java.lang.String, int);
public static int v(TAG, "My log as verbose");
public static int d(TAG, "My log as debug");
public static int i(TAG, "My log as information");
}
Aşağıdaki örnek proguard-rules.pro
dosyası, üretimdeki tüm günlükleri kaldırır:
-assumenosideeffects class android.util.Log {
private static final String TAG = "MyTAG";
public static boolean isLoggable(java.lang.String, int);
public static int v(TAG, "My log as verbose");
public static int d(TAG, "My log as debug");
public static int i(TAG, "My log as information");
public static int w(TAG, "My log as warning");
public static int e(TAG, "My log as error");
}
R8'in uygulama küçültme özellikleri ve günlük kaldırma işlevi sunduğunu unutmayın. R8'i yalnızca günlük ayıklama işlevi için kullanmak istiyorsanız proguard-rules.pro
dosyanıza aşağıdakileri ekleyin:
-dontwarn **
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!code/allocation/variable
-keep class **
-keepclassmembers class *{*;}
-keepattributes *
Üretim ortamındaki hassas veriler içeren tüm günlükleri temizleyin
Hassas verilerin sızmasını önlemek için, logcat
'e yapılan tüm günlük kayıtlarının uygulamanızın hata ayıklama dışı sürümlerinde temizlendiğinden emin olun. Hassas olabilecek tüm verileri kaldırın.
Örnek:
Kotlin
data class Credential<T>(val data: String) {
/** Returns a redacted value to avoid accidental inclusion in logs. */
override fun toString() = "Credential XX"
}
fun checkNoMatches(list: List<Any>) {
if (!list.isEmpty()) {
Log.e(TAG, "Expected empty list, but was %s", list)
}
}
Java
public class Credential<T> {
private T t;
/** Returns a redacted value to avoid accidental inclusion in logs. */
public String toString(){
return "Credential XX";
}
}
private void checkNoMatches(List<E> list) {
if (!list.isEmpty()) {
Log.e(TAG, "Expected empty list, but was %s", list);
}
}
Günlüklerdeki hassas verileri çıkarma
Günlüklerinize hassas veriler eklemeniz gerekiyorsa hassas verileri kaldırmak veya gizlemek için günlükleri yazdırmadan önce temizlemenizi öneririz. Bunu yapmak için aşağıdaki tekniklerden birini kullanın:
- Jeton oluşturma. Hassas veriler, gizli anahtarlara jetonlar aracılığıyla referans verilebilen bir şifreleme yönetimi sistemi gibi bir kasada depolanıyorsa hassas veriler yerine jetonu günlüğe kaydedin.
- Veri maskeleme Veri maskeleme, tek yönlü ve geri alınamayan bir işlemdir. Hassas verilerin, orijinale yapısal olarak benzeyen ancak bir alandaki en hassas bilgileri gizleyen bir sürümünü oluşturur. Örnek:
1234-5678-9012-3456
kredi kartı numarasınınXXXX-XXXX-XXXX-1313
ile değiştirilmesi. Uygulamanızı üretime yayınlamadan önce, veri maskeleme kullanımını incelemek için bir güvenlik incelemesi süreci tamamlamanızı öneririz. Uyarı: Hassas verilerin yalnızca bir kısmının bile güvenliği önemli ölçüde etkileyebileceği durumlarda (ör. şifreler işlenirken) veri maskeleme kullanmayın. - Gizlileştirme. Redaksiyon, maskelemeye benzer ancak bir alandaki tüm bilgileri gizler. Örnek:
1234-5678-9012-3456
kredi kartı numarasınınXXXX-XXXX-XXXX-XXXX
ile değiştirilmesi. - Filtreleme Günlük ifadelerindeki sabit olmayan değerlerin değiştirilmesini kolaylaştırmak için, henüz mevcut değilse tercih ettiğiniz günlük kaydı kitaplığınıza biçim dizelerini uygulayın.
Günlük yazdırma işlemi yalnızca aşağıdaki kod snippet'inde gösterildiği gibi, tüm günlüklerin yazdırılmadan önce temizlenmesini sağlayan bir "günlük temizleyici" bileşeni aracılığıyla gerçekleştirilmelidir.
Kotlin
data class ToMask<T>(private val data: T) {
// Prevents accidental logging when an error is encountered.
override fun toString() = "XX"
// Makes it more difficult for developers to invoke sensitive data
// and facilitates sensitive data usage tracking.
fun getDataToMask(): T = data
}
data class Person(
val email: ToMask<String>,
val username: String
)
fun main() {
val person = Person(
ToMask("name@gmail.com"),
"myname"
)
println(person)
println(person.email.getDataToMask())
}
Java
public class ToMask<T> {
// Prevents accidental logging when an error is encountered.
public String toString(){
return "XX";
}
// Makes it more difficult for developers to invoke sensitive data
// and facilitates sensitive data usage tracking.
public T getDataToMask() {
return this;
}
}
public class Person {
private ToMask<String> email;
private String username;
public Person(ToMask<String> email, String username) {
this.email = email;
this.username = username;
}
}
public static void main(String[] args) {
Person person = new Person(
ToMask("name@gmail.com"),
"myname"
);
System.out.println(person);
System.out.println(person.email.getDataToMask());
}