Категория OWASP: MASVS-CODE: Качество кода
Обзор
Динамическая загрузка кода в приложение создает уровень риска, который необходимо снизить. Злоумышленники потенциально могут подделать или подменить код для доступа к конфиденциальным данным или выполнения вредоносных действий.
Многие формы динамической загрузки кода, особенно те, которые используют удаленные источники, нарушают правила Google Play и могут привести к блокировке вашего приложения из Google Play.
Влияние
Если злоумышленникам удастся получить доступ к коду, который будет загружен в приложение, они смогут изменить его для достижения своих целей. Это может привести к краже данных и эксплойтам выполнения кода. Даже если злоумышленники не могут изменить код для выполнения произвольных действий по своему выбору, они все равно могут повредить или удалить код и тем самым повлиять на доступность приложения.
Смягчения
Избегайте использования динамической загрузки кода
Если нет бизнес-необходимости, избегайте динамической загрузки кода. По возможности вам следует предпочесть включать все функции непосредственно в приложение.
Используйте проверенные источники
Код, который будет загружен в приложение, должен храниться в надежных местах. Что касается локального хранилища, рекомендуется использовать внутреннее хранилище приложения или хранилище с ограниченной областью действия (для Android 10 и более поздних версий). В этих местах предусмотрены меры, позволяющие избежать прямого доступа со стороны других приложений и пользователей.
При загрузке кода из удаленных мест, таких как URL-адреса, по возможности избегайте использования третьих лиц и храните код в своей собственной инфраструктуре, следуя рекомендациям по обеспечению безопасности. Если вам нужно загрузить сторонний код, убедитесь, что поставщик является надежным.
Выполните проверку целостности
Рекомендуется проверить целостность кода, чтобы убедиться, что код не был подделан. Эти проверки следует выполнять перед загрузкой кода в приложение.
При загрузке удаленных ресурсов можно использовать целостность подресурсов для проверки целостности ресурсов, к которым осуществляется доступ.
При загрузке ресурсов из внешнего хранилища используйте проверки целостности, чтобы убедиться, что никакое другое приложение не подделало эти данные или код. Хэши файлов должны храниться безопасным образом, желательно в зашифрованном виде, во внутреннем хранилище.
Котлин
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(bytes.length * 2)
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(bytes.length * 2);
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!");
}
}
}
Подпишите код
Другой вариант обеспечения целостности данных — подписать код и проверить его подпись перед загрузкой. Преимущество этого метода заключается в том, что он также обеспечивает целостность хеш-кода, а не только самого кода, что обеспечивает дополнительную защиту от несанкционированного доступа.
Хотя подписание кода обеспечивает дополнительные уровни безопасности, важно учитывать, что это более сложный процесс, для успешной реализации которого могут потребоваться дополнительные усилия и ресурсы.
Некоторые примеры подписи кода можно найти в разделе «Ресурсы» этого документа.
Ресурсы
- Целостность субресурса
- Цифровая подпись данных
- Подписание кода
- Конфиденциальные данные, хранящиеся во внешнем хранилище