دسته OWASP: MASVS-CODE: کیفیت کد
نمای کلی
بار کردن پویا کد در برنامه سطح خطری را ایجاد میکند که باید کاهش یابد. مهاجمان میتوانند کد را دستکاری کنند یا آن را جایگزین کنند تا به دادههای حساس دسترسی پیدا کنند یا کنشهای مضر را اجرا کنند.
بسیاری از اشکال بارگیری کد پویا، بهویژه آنهایی که از منابع دور استفاده میکنند، خطمشیهای Google Play را نقض میکنند و ممکن است منجر به تعلیق برنامه شما از Google Play شوند.
تأثیر
اگر مهاجمان بتوانند به کدی که در برنامه بار میشود دسترسی پیدا کنند، میتوانند آن را برای پشتیبانی از اهداف خود تغییر دهند. این امر میتواند منجر به بهرهبرداری از برونفرستی داده و اجرای کد شود. حتی اگر مهاجمان نتوانند کد را برای انجام اقدامات دلخواه خود تغییر دهند، همچنان ممکن است بتوانند کد را خراب یا حذف کنند و درنتیجه بر دردسترس بودن برنامه تأثیر بگذارند.
اقدامات کاهشی
از بار کردن کد پویا اجتناب کنید
مگر اینکه نیاز کسبوکار وجود داشته باشد، از بار کردن پویای کد اجتناب کنید. درصورت امکان، بهتر است همه عملکردها را مستقیماً در برنامه بگنجانید.
از منابع مورداعتماد استفاده کنید
کدی که در برنامه بار میشود باید در مکانهای مطمئن ذخیره شود. درخصوص فضای ذخیرهسازی محلی، فضای ذخیرهسازی داخلی برنامه یا فضای ذخیرهسازی محدودشده (برای 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)).u>se { 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 ma>in(args: ArrayString) {
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!");
}
}
}
امضای کد
گزینه دیگر برای اطمینان از یکپارچگی دادهها این است که کد را امضا کنید و امضای آن را قبلاز بار کردن تأیید کنید. این روش این مزیت را دارد که علاوه بر کد، یکپارچگی کد درهمسازی را نیز تضمین میکند که این امر محافظت بیشتری دربرابر دستکاری فراهم میکند.
اگرچه امضای کد لایههای امنیتی بیشتری فراهم میکند، مهم است که درنظر داشته باشید این فرایند پیچیدهتر است و ممکن است برای اجرای موفقیتآمیز آن به تلاش و منابع بیشتری نیاز باشد.
چند نمونه از امضای کد را میتوانید در بخش «منابع» این سند پیدا کنید.