رده OWASP: MASVS-CODE: کیفیت کد
نمای کلی
بارگذاری پویای کد در یک برنامه، سطح ریسکی را ایجاد میکند که باید کاهش یابد. مهاجمان میتوانند به طور بالقوه کد را دستکاری یا جایگزین کنند تا به دادههای حساس دسترسی پیدا کنند یا اقدامات مضری را انجام دهند.
بسیاری از اشکال بارگذاری پویای کد، به ویژه آنهایی که از منابع راه دور استفاده میکنند، سیاستهای گوگل پلی را نقض میکنند و ممکن است منجر به تعلیق برنامه شما از گوگل پلی شوند.
تأثیر
اگر مهاجمان موفق به دسترسی به کدی شوند که در برنامه بارگذاری میشود، میتوانند آن را برای پشتیبانی از اهداف خود تغییر دهند. این امر میتواند منجر به استخراج دادهها و سوءاستفادههای اجرای کد شود. حتی اگر مهاجمان نتوانند کد را برای انجام اقدامات دلخواه خود تغییر دهند، هنوز هم این امکان وجود دارد که بتوانند کد را خراب یا حذف کنند و در نتیجه بر دسترسیپذیری برنامه تأثیر بگذارند.
کاهشها
از بارگذاری پویای کد خودداری کنید
مگر اینکه نیاز تجاری وجود داشته باشد، از بارگذاری پویای کد خودداری کنید. ترجیحاً در صورت امکان، تمام قابلیتها را مستقیماً در برنامه بگنجانید.
از منابع معتبر استفاده کنید
کدی که در برنامه بارگذاری میشود باید در مکانهای قابل اعتماد ذخیره شود. در مورد ذخیرهسازی محلی، ذخیرهسازی داخلی برنامه یا ذخیرهسازی محدود (برای اندروید ۱۰ و بالاتر) مکانهای توصیهشده هستند. این مکانها دارای تمهیداتی برای جلوگیری از دسترسی مستقیم سایر برنامهها و کاربران هستند.
هنگام بارگذاری کد از مکانهای دور مانند 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!");
}
}
}
کد را امضا کنید
گزینه دیگر برای اطمینان از صحت دادهها، امضای کد و تأیید امضای آن قبل از بارگذاری آن است. این روش این مزیت را دارد که نه تنها صحت خود کد، بلکه صحت کد هش را نیز تضمین میکند، که این امر محافظت بیشتری در برابر دستکاری فراهم میکند.
اگرچه امضای کد لایههای امنیتی بیشتری را فراهم میکند، اما باید در نظر داشت که این فرآیند پیچیدهتری است که ممکن است برای اجرای موفقیتآمیز به تلاش و منابع بیشتری نیاز داشته باشد.
برخی از نمونههای امضای کد را میتوانید در بخش منابع این سند بیابید.