Конфиденциальные данные, хранящиеся во внешнем хранилище

Категория OWASP: MASVS-STORAGE: Хранилище

Обзор

Хранение данных во внешнем хранилище без ограниченного хранилища не гарантирует безопасности. Запись конфиденциальных файлов на внешнее хранилище может привести к раскрытию конфиденциальных данных.

Влияние

Если конфиденциальные данные хранятся во внешнем хранилище, любое приложение на устройстве может получить к ним доступ, подвергая данные ненужному риску. Кроме того, если файлы, хранящиеся во внешнем хранилище, затем загружаются в приложение, возможно, что в это время данные могли быть подделаны. Измененные данные могут быть предназначены для обмана пользователей или даже для выполнения кода в загружаемом приложении.

Смягчения

Использовать ограниченное хранилище (Android 10 и более поздних версий)

Для Android версии 10 и более поздних версий можно использовать хранилище с ограниченной областью действия. Это дает возможность использовать внешнее хранилище, одновременно защищая данные от других приложений. При использовании хранилища с ограниченной областью приложения могут получать доступ только к файлам, которые они создали сами, или к файлам, которые находятся в общедоступной папке «Загрузки». Это помогает защитить конфиденциальность и безопасность пользователей.

Использовать внутреннюю память

Если возможно, следует использовать внутреннюю память приложения, особенно для конфиденциальных данных. Доступ к указанному хранилищу ограничен приложением-владельцем, и поэтому его можно считать безопасным, если только устройство не рутировано.

Шифрование конфиденциальных данных

Если конфиденциальные данные хранятся во внешнем хранилище, их следует зашифровать. Рекомендуется использовать надежный алгоритм шифрования и использовать Android KeyStore для безопасного хранения ключа.

Помните, что в целях обеспечения безопасности все конфиденциальные данные должны быть зашифрованы, независимо от того, где они хранятся.

Важно отметить, что полное шифрование диска (или файловое шифрование в Android 10) — это мера, направленная на защиту данных от физического доступа и других векторов атак. В этом конкретном случае конфиденциальные данные должны быть дополнительно зашифрованы приложением.

Выполните проверку целостности

В тех случаях, когда данные или код необходимо загрузить из внешнего хранилища в приложение, рекомендуется выполнить проверку целостности, чтобы убедиться, что никакое другое приложение не подделало эти данные или код. Хэши файлов должны храниться безопасным образом, желательно в зашифрованном виде, во внутреннем хранилище.

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!")
       
}
   
}
}
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!");
       
}
   
}
}

Ресурсы