تحميل الرموز البرمجية الديناميكية
تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
فئة OWASP: MASVS-CODE: جودة الرموز البرمجية
نظرة عامة
يؤدي التحميل الديناميكي للرمز البرمجي في تطبيق إلى حدوث مستوى مخاطر يجب التخفيف منه. قد يتلاعب المهاجمون بالرمز البرمجي أو يستبدلونه للوصول إلى البيانات الحسّاسة أو ينفّذون إجراءات ضارّة.
إنّ العديد من أشكال تحميل الرموز البرمجية الديناميكية، خاصةً تلك التي تستخدم مصادر عن بُعد،
تنتهك سياسات Google Play وقد تؤدي إلى تعليق تطبيقك من
Google Play.
التأثير
إذا تمكّن المهاجمون من الوصول إلى الرمز الذي سيتم تحميله في
التطبيق، يمكنهم تعديله لتحقيق أهدافهم. وقد يؤدي ذلك إلى
عمليات استخراج البيانات واستغلال تنفيذ الرموز البرمجية. حتى إذا لم يتمكّن المهاجمون من تعديل
الرمز البرمجي لتنفيذ إجراءات عشوائية من اختيارهم، يبقى من الممكن أن تتمكّن
المهاجمون من إفساد الرمز البرمجي أو إزالته، ما يؤثر بالتالي في مدى توفّر
التطبيق.
إجراءات التخفيف
تجنُّب استخدام ميزة تحميل الرموز البرمجية الديناميكية
تجنَّب تحميل الرموز الديناميكية ما لم تكن هناك حاجة مرتبطة بالنشاط التجاري. يجب تفضيل
تضمين جميع الوظائف في التطبيق مباشرةً كلما أمكن ذلك.
استخدام مصادر موثوقة
يجب تخزين الرمز الذي سيتم تحميله في التطبيق في مواقع
موثوق بها. في ما يتعلّق بمساحة التخزين على الجهاز، فإنّ مساحة التخزين الداخلية للتطبيق أو مساحة التخزين المقيّدة (لنظام التشغيل Android 10 والإصدارات الأحدث) هما المكانان المُقترَحان. تحتوي هذه المواقع على إجراءات لتجنب الوصول المباشر من التطبيقات والمستخدمين الآخرين.
عند تحميل الرمز من مواقع عن بُعد، مثل عناوين URL، تجنَّب استخدام جهات خارجية
عند الإمكان، واحفظ الرمز في بنيتك الأساسية، مع اتّباع أفضل الممارسات المتعلقة بالتكامل. إذا كنت بحاجة إلى تحميل رمز تابع لجهة خارجية، تأكَّد من أنّ مقدّم الخدمة
موثوق به.
يُنصح بالتحقّق من السلامة لضمان عدم
التلاعب بالرمز. يجب إجراء عمليات الفحص هذه قبل تحميل الرمز في التطبيق.
عند تحميل موارد بعيدة، يمكن استخدام سلامة المورد الفرعي من أجل التحقّق من سلامة الموارد التي تم الوصول إليها.
عند تحميل الموارد من وحدة التخزين الخارجية، استخدِم عمليات التحقّق من السلامة للتحقق من عدم تلاعب أي تطبيق آخر بهذه البيانات أو الرمز البرمجي. يجب تخزين تجزئات
الملفات بطريقة آمنة، ويُفضَّل أن تكون مشفَّرة وفي ملف التخزين
الداخلي.
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(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!")
}
}
}
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(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!");
}
}
}
توقيع الرمز
هناك خيار آخر لضمان سلامة البيانات، وهو توقيع الرمز و
التحقّق من توقيعه قبل تحميله. تتميز هذه الطريقة أيضًا بمحاولة
ضمان سلامة رمز التجزئة، وليس الرمز نفسه فقط، ما يؤدي إلى
توفير حماية إضافية ضد التلاعب.
على الرغم من أن توقيع التعليمات البرمجية يوفر طبقات أمان إضافية، إلا أنه من المهم أن نأخذ في الاعتبار أنها عملية أكثر تعقيدًا قد تتطلب جهدًا وموارد إضافية لكي يتم تنفيذها بنجاح.
يمكن العثور على بعض أمثلة على توقيع الرموز البرمجية في قسم "الموارد" ضمن
هذا المستند.
المراجع
يخضع كل من المحتوى وعيّنات التعليمات البرمجية في هذه الصفحة للتراخيص الموضحّة في ترخيص استخدام المحتوى. إنّ Java وOpenJDK هما علامتان تجاريتان مسجَّلتان لشركة Oracle و/أو الشركات التابعة لها.
تاريخ التعديل الأخير: 2025-07-26 (حسب التوقيت العالمي المتفَّق عليه)
[[["يسهُل فهم المحتوى.","easyToUnderstand","thumb-up"],["ساعَدني المحتوى في حلّ مشكلتي.","solvedMyProblem","thumb-up"],["غير ذلك","otherUp","thumb-up"]],[["لا يحتوي على المعلومات التي أحتاج إليها.","missingTheInformationINeed","thumb-down"],["الخطوات معقدة للغاية / كثيرة جدًا.","tooComplicatedTooManySteps","thumb-down"],["المحتوى قديم.","outOfDate","thumb-down"],["ثمة مشكلة في الترجمة.","translationIssue","thumb-down"],["مشكلة في العيّنات / التعليمات البرمجية","samplesCodeIssue","thumb-down"],["غير ذلك","otherDown","thumb-down"]],["تاريخ التعديل الأخير: 2025-07-26 (حسب التوقيت العالمي المتفَّق عليه)"],[],[],null,["# Dynamic Code Loading\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-CODE: Code Quality](https://mas.owasp.org/MASVS/10-MASVS-CODE)\n\nOverview\n--------\n\nDynamically loading code into an application introduces a risk level that has to\nbe mitigated. Attackers could potentially tamper with or substitute the code to\naccess sensitive data or execute harmful actions.\n\nMany forms of dynamic code loading, especially those that use remote sources,\n[violate Google Play policies](https://support.google.com/googleplay/android-developer/answer/9888379) and may lead to a suspension of your app from\nGoogle Play.\n\nImpact\n------\n\nIf attackers manage to gain access to the code that will be loaded into the\napplication, they could modify it to support their goals. This could lead to\ndata exfiltration and code execution exploits. Even if attackers cannot modify\nthe code to perform arbitrary actions of their choice, it is still possible that\nthey can corrupt or remove the code and thus affect the availability of the\napplication.\n\nMitigations\n-----------\n\n### Avoid using dynamic code loading\n\nUnless there is a business need, avoid dynamic code loading. You should prefer\nto include all functionalities directly into the application, whenever possible.\n\n### Use trusted sources\n\nCode that will be loaded into the application should be stored in trusted\nlocations. Regarding local storage, the application internal storage or scoped\nstorage (for Android 10 and later) are the recommended places. These locations\nhave measures to avoid direct access from other applications and users.\n\nWhen loading code from remote locations such as URLs, avoid using third parties\nwhen possible, and store the code in your own infrastructure, following security\nbest practices. If you need to load third-party code, ensure that the provider\nis a trusted one.\n\n### Perform integrity checks\n\nIntegrity checks are recommended in order to ensure that the code has not been\ntampered with. These checks should be performed before loading code into the\napplication.\n\nWhen loading remote resources, subresource integrity can be used in order to\nvalidate the integrity of the accessed resources.\n\nWhen loading resources from the external storage, use integrity checks to verify\nthat no other application has tampered with this data or code. The hashes of the\nfiles should be stored in a secure manner, preferably encrypted and in the\ninternal storage. \n\n### Kotlin\n\n package com.example.myapplication\n\n import java.io.BufferedInputStream\n import java.io.FileInputStream\n import java.io.IOException\n import java.security.MessageDigest\n import java.security.NoSuchAlgorithmException\n\n object FileIntegrityChecker {\n @Throws(IOException::class, NoSuchAlgorithmException::class)\n fun getIntegrityHash(filePath: String?): String {\n val md = MessageDigest.getInstance(\"SHA-256\") // You can choose other algorithms as needed\n val buffer = ByteArray(8192)\n var bytesRead: Int\n BufferedInputStream(FileInputStream(filePath)).use { fis -\u003e\n while (fis.read(buffer).also { bytesRead = it } != -1) {\n md.update(buffer, 0, bytesRead)\n }\n\n }\n\n private fun bytesToHex(bytes: ByteArray): String {\n val sb = StringBuilder(bytes.length * 2)\n for (b in bytes) {\n sb.append(String.format(\"%02x\", b))\n }\n return sb.toString()\n }\n\n @Throws(IOException::class, NoSuchAlgorithmException::class)\n fun verifyIntegrity(filePath: String?, expectedHash: String): Boolean {\n val actualHash = getIntegrityHash(filePath)\n return actualHash == expectedHash\n }\n\n @Throws(Exception::class)\n @JvmStatic\n fun main(args: Array\u003cString\u003e) {\n val filePath = \"/path/to/your/file\"\n val expectedHash = \"your_expected_hash_value\"\n if (verifyIntegrity(filePath, expectedHash)) {\n println(\"File integrity is valid!\")\n } else {\n println(\"File integrity is compromised!\")\n }\n }\n }\n\n### Java\n\n package com.example.myapplication;\n\n import java.io.BufferedInputStream;\n import java.io.FileInputStream;\n import java.io.IOException;\n import java.security.MessageDigest;\n import java.security.NoSuchAlgorithmException;\n\n public class FileIntegrityChecker {\n\n public static String getIntegrityHash(String filePath) throws IOException, NoSuchAlgorithmException {\n MessageDigest md = MessageDigest.getInstance(\"SHA-256\"); // You can choose other algorithms as needed\n byte[] buffer = new byte[8192];\n int bytesRead;\n\n try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(filePath))) {\n while ((bytesRead = fis.read(buffer)) != -1) {\n md.update(buffer, 0, bytesRead);\n }\n }\n\n byte[] digest = md.digest();\n return bytesToHex(digest);\n }\n\n private static String bytesToHex(byte[] bytes) {\n StringBuilder sb = new StringBuilder(bytes.length * 2);\n for (byte b : bytes) {\n sb.append(String.format(\"%02x\", b));\n }\n return sb.toString();\n }\n\n public static boolean verifyIntegrity(String filePath, String expectedHash) throws IOException, NoSuchAlgorithmException {\n String actualHash = getIntegrityHash(filePath);\n return actualHash.equals(expectedHash);\n }\n\n public static void main(String[] args) throws Exception {\n String filePath = \"/path/to/your/file\";\n String expectedHash = \"your_expected_hash_value\";\n\n if (verifyIntegrity(filePath, expectedHash)) {\n System.out.println(\"File integrity is valid!\");\n } else {\n System.out.println(\"File integrity is compromised!\");\n }\n }\n }\n\n### Sign the code\n\nAnother option to ensure the integrity of the data is to sign the code and\nverify its signature before loading it. This method has the advantage of also\nensuring the integrity of the hash code, not only the code itself, which\nprovides an additional anti-tampering protection.\n\nAlthough code signing provides additional security layers, it is important to\ntake into account that it is a more complex process that may require additional\neffort and resources to be successfully implemented.\n\nSome examples of code signing can be found in the Resources section of this\ndocument.\n\nResources\n---------\n\n- [Subresource Integrity](https://en.wikipedia.org/wiki/Subresource_Integrity)\n- [Digitally Sign Data](https://developers.google.com/tink/digitally-sign-data#java)\n- [Code Signing](https://en.wikipedia.org/wiki/Code_signing)\n- [Sensitive Data Stored in External Storage](/privacy-and-security/risks/sensitive-data-external-storage)"]]