Harici Depolama Alanlarında Depolanan Hassas Veriler

OWASP kategorisi: MASVS-STORAGE: Depolama

Genel Bakış

Android 10 (API 29) veya önceki sürümleri hedefleyen uygulamalar kapsamlı depolamayı zorunlu kılmaz. Bu durumda, harici depolama alanında saklanan tüm verilere READ_EXTERNAL_STORAGE izni olan diğer uygulamalar erişebilir.

Etki

Android 10'u (API 29) veya daha eski bir sürümü hedefleyen uygulamalarda hassas veriler harici depolama alanında depolanıyorsa cihazdaki READ_EXTERNAL_STORAGE iznine sahip tüm uygulamalar bu verilere erişebilir. Bu durum, kötü amaçlı uygulamaların harici depolama alanında kalıcı veya geçici olarak depolanan hassas dosyalara sessizce erişmesine olanak tanır. Ayrıca, harici depolama alanındaki içeriğe sistemdeki herhangi bir uygulama tarafından erişilebildiğinden, WRITE_EXTERNAL_STORAGE iznini de bildiren kötü amaçlı uygulamalar, harici depolama alanında depolanan dosyaları (ör. kötü amaçlı veriler eklemek için) değiştirebilir. Uygulamaya yüklenen bu kötü amaçlı veriler, kullanıcıları yanıltmak veya kod yürütmek için tasarlanmış olabilir.

Çözümler

Kapsamlı depolama (Android 10 ve sonraki sürümler)

Android 10

Android 10'u hedefleyen uygulamalarda geliştiriciler, kapsamlı depolamayı açıkça etkinleştirebilir. Bu, AndroidManifest.xml dosyasında requestLegacyExternalStorage işaretini false olarak ayarlayarak yapılabilir. Kapsamlı depolama ile uygulamalar, harici depolama alanında yalnızca kendilerinin oluşturduğu dosyalara veya MediaStore API kullanılarak depolanan dosya türlerine (ör. ses ve video) erişebilir. Bu, kullanıcı gizliliğini ve güvenliğini korumaya yardımcı olur.

Android 11 ve sonraki sürümler

Android 11 veya sonraki sürümleri hedefleyen uygulamalarda işletim sistemi kapsamlı depolama kullanımını zorunlu kılar. Yani requestLegacyExternalStorage işaretini yok sayar ve uygulamaların harici depolama alanını istenmeyen erişime karşı otomatik olarak korur.

Hassas Veriler İçin Dahili Depolama Alanını Kullanma

Hedeflenen Android sürümünden bağımsız olarak, bir uygulamanın hassas verileri her zaman dahili depolamada saklanmalıdır. Android sanal alanı sayesinde dahili depolama alanına erişim, otomatik olarak sahip olan uygulamayla sınırlandırılır. Bu nedenle, cihazda root işlemi yapılmadığı sürece güvenli olduğu kabul edilebilir.

Hassas verileri şifreleme

Uygulamanın kullanım alanları, hassas verilerin harici depolama alanında saklanmasını gerektiriyorsa veriler şifrelenmelidir. Anahtarı güvenli bir şekilde depolamak için Android KeyStore'un kullanıldığı güçlü bir şifreleme algoritması önerilir.

Genel olarak, hassas verilerin depolandığı yer fark etmeksizin tüm hassas verilerin şifrelenmesi önerilen bir güvenlik uygulamasıdır.

Tam disk şifrelemenin (veya Android 10'dan itibaren dosya tabanlı şifrelemenin) verileri fiziksel erişime ve diğer saldırı vektörlerine karşı korumayı amaçlayan bir önlem olduğunu unutmamak önemlidir. Bu nedenle, aynı güvenlik önlemini sağlamak için harici depolama alanında tutulan hassas veriler uygulama tarafından da şifrelenmelidir.

Bütünlük kontrolleri gerçekleştirme

Verilerin veya kodun harici depolama alanından uygulamaya yüklenmesi gerektiği durumlarda, başka bir uygulamanın bu verilerle veya kodla oynamadığını doğrulamak için bütünlük kontrolleri yapılması önerilir. Dosyaların karma değerleri güvenli bir şekilde, tercihen şifrelenmiş olarak ve dahili depolama alanında saklanmalıdır.

Kotlin

package com.example.myapplication

import java.io.BufferedInputStream
import java.io.FileInputStream
import java.io.IOException
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException

object FileIntegrityChecker {
    @Throws(IOException::class, NoSuchAlgorithmException::class)
    fun getIntegrityHash(filePath: String?): String {
        val md = MessageDigest.getInstance("SHA-256") // You can choose other algorithms as needed
        val buffer = ByteArray(8192)
        var bytesRead: Int
        BufferedInputStream(FileInputStream(filePath)).use { fis ->
            while (fis.read(buffer).also { bytesRead = it } != -1) {
                md.update(buffer, 0, bytesRead)
            }

    }

    private fun bytesToHex(bytes: ByteArray): String {
        val sb = StringBuilder()
        for (b in bytes) {
            sb.append(String.format("%02x", b))
        }
        return sb.toString()
    }

    @Throws(IOException::class, NoSuchAlgorithmException::class)
    fun verifyIntegrity(filePath: String?, expectedHash: String): Boolean {
        val actualHash = getIntegrityHash(filePath)
        return actualHash == expectedHash
    }

    @Throws(Exception::class)
    @JvmStatic
    fun main(args: Array<String>) {
        val filePath = "/path/to/your/file"
        val expectedHash = "your_expected_hash_value"
        if (verifyIntegrity(filePath, expectedHash)) {
            println("File integrity is valid!")
        } else {
            println("File integrity is compromised!")
        }
    }
}

Java

package com.example.myapplication;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class FileIntegrityChecker {

    public static String getIntegrityHash(String filePath) throws IOException, NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256"); // You can choose other algorithms as needed
        byte[] buffer = new byte[8192];
        int bytesRead;

        try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(filePath))) {
            while ((bytesRead = fis.read(buffer)) != -1) {
                md.update(buffer, 0, bytesRead);
            }
        }

        byte[] digest = md.digest();
        return bytesToHex(digest);
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    public static boolean verifyIntegrity(String filePath, String expectedHash) throws IOException, NoSuchAlgorithmException {
        String actualHash = getIntegrityHash(filePath);
        return actualHash.equals(expectedHash);
    }

    public static void main(String[] args) throws Exception {
        String filePath = "/path/to/your/file";
        String expectedHash = "your_expected_hash_value";

        if (verifyIntegrity(filePath, expectedHash)) {
            System.out.println("File integrity is valid!");
        } else {
            System.out.println("File integrity is compromised!");
        }
    }
}

Kaynaklar