من خلال تعزيز أمان تطبيقك، يمكنك المساعدة في الحفاظ على ثقة المستخدمين وسلامة الأجهزة.
تعرض هذه الصفحة العديد من أفضل الممارسات التي لها تأثير إيجابي كبير على أمان تطبيقك.
فرض التواصل الآمن
عند حماية البيانات التي يتم تبادلها بين تطبيقك والتطبيقات الأخرى، أو بين تطبيقك وموقع إلكتروني، فإنّك تحسّن من ثبات تطبيقك وتحمي البيانات التي ترسلها وتتلقّاها.
حماية الاتصال بين التطبيقات
للتواصل بين التطبيقات بشكل أكثر أمانًا، استخدِم النوايا الضمنية مع أداة اختيار التطبيقات، والأذونات المستندة إلى التوقيع، وموفّري المحتوى غير المُصدَّرين.
عرض أداة اختيار التطبيقات
إذا كان بإمكان نية ضمنية تشغيل تطبيقَين محتملَين على الأقل على جهاز المستخدم، يجب عرض أداة اختيار التطبيقات بشكل صريح. تتيح استراتيجية التفاعل هذه للمستخدمين نقل معلومات حساسة إلى تطبيق يثقون به.
Kotlin
val intent = Intent(Intent.ACTION_SEND)
val possibleActivitiesList: List<ResolveInfo> =
packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)
// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size > 1) {
// Create intent to show chooser.
// Title is something similar to "Share this photo with."
<b>val chooser = resources.getString(R.string.chooser_title).let { title ->
Intent.createChooser(intent, title)
}
startActivity(chooser)</b>
} else if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
Java
Intent intent = new Intent(Intent.ACTION_SEND);
List<ResolveInfo> possibleActivitiesList = getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_ALL);
// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size() > 1) {
// Create intent to show chooser.
// Title is something similar to "Share this photo with."
<b>String title = getResources().getString(R.string.chooser_title);
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);</b>
} else if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
معلومات ذات صلة:
تطبيق الأذونات المستندة إلى التوقيع
عند مشاركة البيانات بين تطبيقَين تتحكّم فيهما أو تملكهما، استخدِم أذونات مستندة إلى التوقيع، إذ لا تتطلّب هذه الأذونات تأكيدًا من المستخدم، بل تتحقّق من أنّ التطبيقات التي تصل إلى البيانات موقَّعة باستخدام مفتاح التوقيع نفسه. وبالتالي، توفّر هذه الأذونات تجربة أكثر سلاسة وأمانًا للمستخدم.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <permission android:name="my_custom_permission_name" android:protectionLevel="signature" />
معلومات ذات صلة:
عدم السماح بالوصول إلى موفّري المحتوى في تطبيقك
ما لم تكن تنوي إرسال بيانات من تطبيقك إلى تطبيق آخر لا تملكه، عليك منع تطبيقات المطوّرين الآخرين بشكل صريح من الوصول إلى عناصر ContentProvider في تطبيقك. وتكتسب هذه الإعدادات أهمية خاصة إذا كان يمكن تثبيت تطبيقك على الأجهزة التي تعمل بالإصدار 4.1.1 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 16) أو الإصدارات الأقدم، لأنّ السمة android:exported الخاصة بالعنصر <provider> تكون true تلقائيًا في هذه الإصدارات من نظام التشغيل Android.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <application ... > <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.myapp.fileprovider" ... android:exported="false"> <!-- Place child elements of <provider> here. --> </provider> ... </application> </manifest>
طلب بيانات الاعتماد قبل عرض المعلومات الحسّاسة
عند طلب بيانات اعتماد من المستخدمين ليتمكّنوا من الوصول إلى معلومات حساسة أو محتوى مميّز في تطبيقك، اطلب منهم إدخال رقم تعريف شخصي أو كلمة مرور أو نقش أو بيانات اعتماد خاصة بالمقاييس الحيوية، مثل التعرّف على الوجه أو بصمة الإصبع.
لمزيد من المعلومات عن كيفية طلب بيانات اعتماد المقاييس الحيوية، يُرجى الاطّلاع على الدليل حول المصادقة بالمقاييس الحيوية.
تطبيق إجراءات أمان الشبكة
توضّح الأقسام التالية كيفية تحسين أمان الشبكة في تطبيقك.
استخدام عدد الزيارات عبر بروتوكول أمان طبقة النقل (TLS)
إذا كان تطبيقك يتواصل مع خادم ويب لديه شهادة صادرة عن هيئة إصدار شهادات (CA) معروفة وموثوق بها، استخدِم طلب HTTPS على النحو التالي:
Kotlin
val url = URL("https://www.google.com")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.connect()
urlConnection.inputStream.use {
...
}
Java
URL url = new URL("https://www.google.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
InputStream in = urlConnection.getInputStream();
إضافة إعدادات أمان الشبكة
إذا كان تطبيقك يستخدم هيئات جديدة أو مخصّصة لإصدار الشهادات، يمكنك تحديد إعدادات أمان شبكتك في ملف إعدادات. تتيح لك هذه العملية إنشاء الإعدادات بدون تعديل أي رمز برمجي للتطبيق.
لإضافة ملف إعدادات أمان الشبكة إلى تطبيقك، اتّبِع الخطوات التالية:
- عليك الإفصاح عن الإعدادات في بيان التطبيق:
-
أضِف ملف موارد XML، الذي يقع في
res/xml/network_security_config.xml.حدِّد أنّه يجب استخدام بروتوكول HTTPS في جميع الزيارات إلى نطاقات معيّنة من خلال إيقاف النص العادي:
<network-security-config> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">secure.example.com</domain> ... </domain-config> </network-security-config>
أثناء عملية التطوير، يمكنك استخدام العنصر
<debug-overrides>للسماح صراحةً بالشهادات التي يثبّتها المستخدم. يؤدي هذا العنصر إلى إلغاء خيارات الأمان المهمة في تطبيقك أثناء تصحيح الأخطاء واختبارها بدون التأثير في إعدادات إصدار التطبيق. يوضّح المقتطف التالي كيفية تحديد هذا العنصر في ملف XML الخاص بإعدادات أمان الشبكة في تطبيقك:<network-security-config> <debug-overrides> <trust-anchors> <certificates src="user" /> </trust-anchors> </debug-overrides> </network-security-config>
<manifest ... > <application android:networkSecurityConfig="@xml/network_security_config" ... > <!-- Place child elements of <application> element here. --> </application> </manifest>
معلومات ذات صلة: ضبط أمان الشبكة
إنشاء مدير الثقة الخاص بك
يجب ألا يقبل مدقق TLS كل شهادة. قد تحتاج إلى إعداد أداة إدارة الثقة والتعامل مع جميع تحذيرات بروتوكول أمان طبقة النقل (TLS) التي تظهر إذا انطبق أحد الشروط التالية على حالة الاستخدام:
- أنت تتواصل مع خادم ويب لديه شهادة موقَّعة من هيئة إصدار شهادات جديدة أو مخصّصة.
- لا يثق الجهاز الذي تستخدمه في هيئة إصدار الشهادات هذه.
- لا يمكنك استخدام إعداد أمان الشبكات.
لمزيد من المعلومات حول كيفية إكمال هذه الخطوات، راجِع المناقشة حول التعامل مع جهة إصدار شهادات غير معروفة.
معلومات ذات صلة:
استخدام عناصر WebView بعناية
WebView
يجب ألا تسمح العناصر في تطبيقك للمستخدمين بالانتقال إلى مواقع إلكترونية خارج نطاق تحكُّمك. استخدِم قائمة السماح كلما أمكن ذلك لحصر المحتوى الذي يتم تحميله بواسطة عناصر WebView في تطبيقك.
بالإضافة إلى ذلك، لا تفعِّل إمكانية استخدام واجهة JavaScript إلا إذا كنت تتحكّم بشكل كامل في المحتوى في كائنات WebView الخاصة بتطبيقك وتثق به.
استخدام قنوات رسائل HTML
إذا كان تطبيقك يحتاج إلى استخدام ميزة التوافق مع واجهة JavaScript على الأجهزة التي تعمل بالإصدار 6.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 23) والإصدارات الأحدث، استخدِم قنوات رسائل HTML بدلاً من التواصل بين موقع إلكتروني وتطبيقك، كما هو موضّح في مقتطف الرمز البرمجي التالي:
Kotlin
val myWebView: WebView = findViewById(R.id.webview)
// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
val channel: Array<out WebMessagePort> = myWebView.createWebMessageChannel()
// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() {
override fun onMessage(port: WebMessagePort, message: WebMessage) {
Log.d(TAG, "On port $port, received this message: $message")
}
})
// Send a message from channel[1] to channel[0].
channel[1].postMessage(WebMessage("My secure message"))
Java
WebView myWebView = (WebView) findViewById(R.id.webview);
// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
WebMessagePort[] channel = myWebView.createWebMessageChannel();
// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
@Override
public void onMessage(WebMessagePort port, WebMessage message) {
Log.d(TAG, "On port " + port + ", received this message: " + message);
}
});
// Send a message from channel[1] to channel[0].
channel[1].postMessage(new WebMessage("My secure message"));
معلومات ذات صلة:
منح الأذونات المناسبة
يجب طلب الحد الأدنى من الأذونات اللازمة لكي يعمل تطبيقك بشكل سليم. وعند الإمكان، يجب التخلي عن الأذونات عندما لا يحتاج إليها تطبيقك.
استخدام الأهداف لتأجيل طلب الأذونات
تجنَّب إضافة إذن إلى تطبيقك لإكمال إجراء يمكن إكماله في تطبيق آخر، واستخدِم بدلاً من ذلك هدفًا لتأجيل الطلب إلى تطبيق آخر لديه الإذن اللازم.
يوضّح المثال التالي كيفية استخدام intent لتوجيه المستخدمين إلى تطبيق جهات الاتصال بدلاً من طلب الأذونات READ_CONTACTS وWRITE_CONTACTS:
Kotlin
// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent(Intent.ACTION_INSERT).apply {
type = ContactsContract.Contacts.CONTENT_TYPE
}.also { intent ->
// Make sure that the user has a contacts app installed on their device.
intent.resolveActivity(packageManager)?.run {
startActivity(intent)
}
}
Java
// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent insertContactIntent = new Intent(Intent.ACTION_INSERT);
insertContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);
// Make sure that the user has a contacts app installed on their device.
if (insertContactIntent.resolveActivity(getPackageManager()) != null) {
startActivity(insertContactIntent);
}
بالإضافة إلى ذلك، إذا كان تطبيقك بحاجة إلى تنفيذ عمليات إدخال/إخراج مستندة إلى الملفات، مثل الوصول إلى مساحة التخزين أو اختيار ملف، لن يحتاج إلى أذونات خاصة لأنّ النظام يمكنه إكمال العمليات نيابةً عن تطبيقك. والأفضل من ذلك، بعد أن يختار المستخدم محتوًى في عنوان URI معيّن، يتم منح التطبيق الذي يطلب المحتوى إذن الوصول إلى المرجع المحدّد.
معلومات ذات صلة:
مشاركة البيانات بأمان بين التطبيقات
اتّبِع أفضل الممارسات التالية لمشاركة محتوى تطبيقك مع تطبيقات أخرى بطريقة أكثر أمانًا:
- فرض أذونات القراءة فقط أو الكتابة فقط حسب الحاجة
-
امنح العملاء إذن الوصول إلى البيانات لمرة واحدة باستخدام علامتَي
FLAG_GRANT_READ_URI_PERMISSIONوFLAG_GRANT_WRITE_URI_PERMISSION. - عند مشاركة البيانات، استخدِم معرّفات الموارد الموحّدة
content://وليس معرّفات الموارد الموحّدةfile://، إذ إنّ مثيلاتFileProviderتفعل ذلك نيابةً عنك.
يوضّح مقتطف الرمز التالي كيفية استخدام علامات منح إذن عنوان URI وأذونات موفّر المحتوى لعرض ملف PDF تابع لتطبيق في تطبيق منفصل لعرض ملفات PDF:
Kotlin
// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("<b>content:</b>//com.example/personal-info.pdf")
// This flag gives the started app read access to the file.
<b>addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)</b>
}.also { intent ->
// Make sure that the user has a PDF viewer app installed on their device.
intent.resolveActivity(packageManager)?.run {
startActivity(intent)
}
}
Java
// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent viewPdfIntent = new Intent(Intent.ACTION_VIEW);
viewPdfIntent.setData(Uri.parse("<b>content://</b>com.example/personal-info.pdf"));
// This flag gives the started app read access to the file.
<b>viewPdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);</b>
// Make sure that the user has a PDF viewer app installed on their device.
if (viewPdfIntent.resolveActivity(getPackageManager()) != null) {
startActivity(viewPdfIntent);
}
ملاحظة: يُعد تنفيذ الملفات من دليل الصفحة الرئيسية للتطبيق القابل للكتابة انتهاكًا لقاعدة W^X. لهذا السبب، لا يمكن للتطبيقات غير الموثوق بها التي تستهدف الإصدار 10 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 29) والإصدارات الأحدث استدعاء exec() على الملفات داخل دليل الصفحة الرئيسية للتطبيق، بل يمكنها استدعاء الرمز الثنائي المضمّن في ملف APK الخاص بالتطبيق فقط. بالإضافة إلى ذلك، لا يمكن للتطبيقات التي تستهدف الإصدار 10 من نظام التشغيل Android والإصدارات الأحدث تعديل الرمز القابل للتنفيذ من الملفات التي تم فتحها باستخدام dlopen() في الذاكرة، ويشمل ذلك أي ملفات كائن مشترَك (.so) تحتوي على عمليات نقل نصية.
معلومات ذات صلة:
android:grantUriPermissions
تخزين البيانات بأمان
على الرغم من أنّ تطبيقك قد يتطلّب الوصول إلى معلومات حسّاسة للمستخدمين، لا يمنح المستخدمون تطبيقك إذن الوصول إلى بياناتهم إلا إذا كانوا يثقون في أنّك تحافظ عليها بشكل سليم.
تخزين البيانات الخاصة في مساحة التخزين الداخلية
يجب تخزين جميع بيانات المستخدمين الخاصة في وحدة التخزين الداخلية للجهاز، والتي يتم عزلها في مساحة آمنة لكل تطبيق. ولا يحتاج تطبيقك إلى طلب إذن لعرض هذه الملفات، ولا يمكن للتطبيقات الأخرى الوصول إليها. وكإجراء أمان إضافي، عندما يزيل المستخدم تطبيقًا، يحذف الجهاز جميع الملفات التي حفظها التطبيق في وحدة التخزين الداخلية.
يوضّح مقتطف الرمز التالي إحدى طرق كتابة البيانات إلى وحدة التخزين الداخلية:
Kotlin
// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
val FILE_NAME = "sensitive_info.txt"
val fileContents = "This is some top-secret information!"
File(filesDir, FILE_NAME).bufferedWriter().use { writer ->
writer.write(fileContents)
}
Java
// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
final String FILE_NAME = "sensitive_info.txt";
String fileContents = "This is some top-secret information!";
try (BufferedWriter writer =
new BufferedWriter(new FileWriter(new File(getFilesDir(), FILE_NAME)))) {
writer.write(fileContents);
} catch (IOException e) {
// Handle exception.
}
يوضّح مقتطف الرمز التالي العملية العكسية، أي قراءة البيانات من وحدة التخزين الداخلية:
Kotlin
val FILE_NAME = "sensitive_info.txt"
val contents = File(filesDir, FILE_NAME).bufferedReader().useLines { lines ->
lines.fold("") { working, line ->
"$working\n$line"
}
}
Java
final String FILE_NAME = "sensitive_info.txt";
StringBuffer stringBuffer = new StringBuffer();
try (BufferedReader reader =
new BufferedReader(new FileReader(new File(getFilesDir(), FILE_NAME)))) {
String line = reader.readLine();
while (line != null) {
stringBuffer.append(line).append('\n');
line = reader.readLine();
}
} catch (IOException e) {
// Handle exception.
}
معلومات ذات صلة:
تخزين البيانات في وحدة تخزين خارجية استنادًا إلى حالة الاستخدام
استخدِم مساحة التخزين الخارجية للملفات الكبيرة وغير الحساسة الخاصة بتطبيقك، بالإضافة إلى الملفات التي يشاركها تطبيقك مع التطبيقات الأخرى. تعتمد واجهات برمجة التطبيقات المحدّدة التي تستخدمها على ما إذا كان تطبيقك مصمَّمًا للوصول إلى الملفات الخاصة بالتطبيق أو الوصول إلى الملفات المشترَكة.
إذا كان الملف لا يحتوي على معلومات خاصة أو حساسة، ولكنّه يقدّم قيمة للمستخدم فقط في تطبيقك، يمكنك تخزين الملف في دليل خاص بالتطبيق على وحدة التخزين الخارجية.
إذا كان تطبيقك يحتاج إلى الوصول إلى ملف أو تخزينه، وكان هذا الملف يقدّم قيمة لتطبيقات أخرى، استخدِم إحدى واجهات برمجة التطبيقات التالية، حسب حالة الاستخدام:
- ملفات الوسائط: لتخزين الصور والملفات الصوتية والفيديوهات التي تتم مشاركتها بين التطبيقات والوصول إليها، استخدِم واجهة برمجة التطبيقات Media Store.
- الملفات الأخرى: لتخزين أنواع أخرى من الملفات المشترَكة والوصول إليها، بما في ذلك الملفات التي تم تنزيلها، استخدِم Storage Access Framework.
التحقّق من توفّر وحدة تخزين
إذا كان تطبيقك يتفاعل مع جهاز تخزين خارجي قابل للإزالة، ضَع في اعتبارك أنّ المستخدم قد يزيل جهاز التخزين أثناء محاولة تطبيقك الوصول إليه. أدرِج منطقًا للتحقّق من توفّر جهاز التخزين.
التحقّق من صحة البيانات
إذا كان تطبيقك يستخدم بيانات من وحدة التخزين الخارجية، تأكَّد من أنّ محتوى البيانات لم يتلف أو يتم تعديله. أدرِج منطقًا للتعامل مع الملفات التي لم تعُد بتنسيق ثابت.
يتضمّن مقتطف الرمز التالي مثالاً على أداة التحقّق من التجزئة:
Kotlin
val hash = calculateHash(stream)
// Store "expectedHash" in a secure location.
if (hash == <var>expectedHash</var>) {
// Work with the content.
}
// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
suspend fun calculateHash(stream: InputStream): String {
return withContext(Dispatchers.IO) {
val digest = MessageDigest.getInstance("SHA-512")
val digestStream = DigestInputStream(stream, digest)
while (digestStream.read() != -1) {
// The DigestInputStream does the work; nothing for us to do.
}
digest.digest().joinToString(":") { "%02x".format(it) }
}
}
Java
Executor threadPoolExecutor = Executors.newFixedThreadPool(4);
private interface HashCallback {
void onHashCalculated(@Nullable String hash);
}
boolean hashRunning = calculateHash(inputStream, threadPoolExecutor, hash -> {
if (Objects.equals(hash, <var>expectedHash</var>)) {
// Work with the content.
}
});
if (!hashRunning) {
// There was an error setting up the hash function.
}
private boolean calculateHash(@NonNull InputStream stream,
@NonNull Executor executor,
@NonNull HashCallback hashCallback) {
final MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException nsa) {
return false;
}
// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
executor.execute(() -> {
String hash;
try (DigestInputStream digestStream =
new DigestInputStream(stream, digest)) {
while (digestStream.read() != -1) {
// The DigestInputStream does the work; nothing for us to do.
}
StringBuilder builder = new StringBuilder();
for (byte aByte : digest.digest()) {
builder.append(String.format("%02x", aByte)).append(':');
}
hash = builder.substring(0, builder.length() - 1);
} catch (IOException e) {
hash = null;
}
final String calculatedHash = hash;
runOnUiThread(() -> hashCallback.onHashCalculated(calculatedHash));
});
return true;
}
استخدام وحدة التخزين الداخلية لبيانات ذاكرة التخزين المؤقت الحساسة
لتوفير وصول أسرع إلى بيانات التطبيق، يمكنك تخزينها في ذاكرة التخزين المؤقت للجهاز. بالنسبة إلى ذاكرات التخزين المؤقت التي تبلغ سعتها 1 ميغابايت أو أقل، استخدِم getCacheDir(). أما بالنسبة إلى ذاكرات التخزين المؤقت التي تزيد سعتها عن 1 ميغابايت، فاستخدِم getExternalCacheDir(). يوفّر لك كلا الطريقتين العنصر File الذي يحتوي على بيانات تطبيقك المخزّنة مؤقتًا.
مع أنّ دليل ذاكرة التخزين المؤقت الداخلية (الذي توفّره getCacheDir()) خاص بتطبيقك، إلا أنّ دليل ذاكرة التخزين المؤقت الخارجية ليس كذلك.
يوضّح مقتطف الرمز التالي كيفية تخزين ملف نزّله تطبيقك مؤخرًا في ذاكرة التخزين المؤقت:
Kotlin
val cacheFile = File(myDownloadedFileUri).let { fileToCache ->
File(cacheDir.path, fileToCache.name)
}
Java
File cacheDir = getCacheDir();
File fileToCache = new File(myDownloadedFileUri);
String fileToCacheName = fileToCache.getName();
File cacheFile = new File(cacheDir.getPath(), fileToCacheName);
ملاحظة: إذا كنت تستخدم
getExternalCacheDir() لوضع ذاكرة التخزين المؤقت لتطبيقك في مساحة تخزين مشتركة، قد يزيل المستخدم وسائط التخزين هذه أثناء تشغيل تطبيقك. لذا، عليك تضمين منطق للتعامل بشكل سليم مع البيانات غير المتوفرة في ذاكرة التخزين المؤقت بسبب سلوك المستخدم هذا.
تنبيه: لا يتم فرض أي إجراءات أمان على الملفات
في دليل ذاكرة التخزين المؤقت الخارجية.
وبالتالي، يمكن لأي تطبيق يستهدف الإصدار 10 من نظام التشغيل Android (المستوى 29 لواجهة برمجة التطبيقات) أو الإصدارات الأقدم ولديه إذن WRITE_EXTERNAL_STORAGE الوصول إلى محتوى ذاكرة التخزين المؤقت هذه.
معلومات ذات صلة: نظرة عامة على تخزين البيانات والملفات
استخدام SharedPreferences في الوضع الخاص
عند استخدام
getSharedPreferences() لإنشاء أو الوصول إلى عناصر SharedPreferences في تطبيقك،
استخدِم MODE_PRIVATE. بهذه الطريقة، لن يتمكّن سوى تطبيقك من الوصول إلى المعلومات الواردة في ملف الإعدادات المفضّلة المشتركة.
إذا كنت تريد مشاركة البيانات بين التطبيقات، لا تستخدِم عناصر SharedPreferences، بل اتّبِع الخطوات لمشاركة البيانات بأمان بين التطبيقات.
معلومات ذات صلة:
تحديث الخدمات والتبعيات باستمرار
تستخدم معظم التطبيقات مكتبات خارجية ومعلومات نظام الجهاز لإكمال مهام متخصصة. ومن خلال الحفاظ على تحديثات التبعيات في تطبيقك، يمكنك تعزيز أمان نقاط الاتصال هذه.
التحقّق من مقدّم خدمات الأمان في "خدمات Google Play"
ملاحظة: لا ينطبق هذا القسم إلا على التطبيقات التي تستهدف الأجهزة التي تم تثبيت خدمات Google Play عليها.
إذا كان تطبيقك يستخدم "خدمات Google Play"، تأكَّد من تحديثها على الجهاز الذي تم تثبيت تطبيقك عليه. إجراء عملية التحقّق بشكل غير متزامن، خارج سلسلة التعليمات البرمجية لواجهة المستخدم إذا لم يكن الجهاز مُحدَّثًا، سيحدث خطأ في التفويض.
لتحديد ما إذا كانت "خدمات Google Play" محدَّثة على الجهاز الذي تم تثبيت تطبيقك عليه، اتّبِع الخطوات الواردة في الدليل حول تحديث موفّر الأمان للحماية من الثغرات الأمنية في بروتوكول SSL.
معلومات ذات صلة:
تعديل جميع تبعيات التطبيق
قبل نشر تطبيقك، تأكَّد من أنّ جميع المكتبات وحِزم SDK وغيرها من التبعيات محدّثة:
- بالنسبة إلى التبعيات التابعة للطرف الأول، مثل حزمة تطوير البرامج (SDK) لنظام التشغيل Android، استخدِم أدوات التحديث المتوفّرة في "استوديو Android"، مثل SDK Manager.
- بالنسبة إلى العناصر التابعة الخارجية، يمكنك الاطّلاع على المواقع الإلكترونية للمكتبات التي يستخدمها تطبيقك وتثبيت أي تحديثات ورموز تصحيح أمان متوفّرة.
معلومات ذات صلة: إضافة عناصر معتمدة في الإصدار
مزيد من المعلومات
لمزيد من المعلومات حول كيفية تعزيز أمان تطبيقك، اطّلِع على المراجع التالية:
- قائمة التحقّق من أمان الجودة الأساسية للتطبيق
- برنامج تحسين أمان التطبيقات
- قناة "مطوّرو تطبيقات Android" على YouTube
- Android ميزة "التأكيد المحمي": الارتقاء بأمان المعاملات إلى المستوى التالي