معلومات التحدي
هذا التحدي مصمم لمتخصصي الأمن السيبراني الذين يرغبون في تطوير مهاراتهم في تحليل وتأمين تطبيقات Android. ستتعلم من خلاله تقنيات متقدمة لاكتشاف الثغرات الأمنية وكيفية معالجتها.
المستوى
متوسط
المدة المتوقعة
1-2 ساعات
الأدوات المطلوبة
Android Studio, ADB, Burp Suite, Frida
النقاط
150 نقطة
سيناريو التحدي
أنت محلل أمني في شركة تقنية، وقد طُلِب منك تحليل تطبيق Android خاص بالخدمات المصرفية للكشف عن أي ثغرات أمنية محتملة. التطبيق يحتوي على عدة نقاط ضعف يجب اكتشافها وتقديم تقرير عنها.
التحدي الأول: ثغرة تخزين البيانات غير الآمن
متوسطاكتشف أن التطبيق يقوم بتخزين بيانات حساسة (كلمات المرور، tokens) في SharedPreferences وهي غير آمنة. حدد مكان التخزين غير الآمن واقترح حلاً مناسباً.
public void saveCredentials(String username, String password) {
SharedPreferences prefs = getSharedPreferences("user_data", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("username", username);
editor.putString("password", password);
editor.apply();
Log.d("App", "تم حفظ بيانات الاعتماد");
}
تلميح
ابحث عن كيفية تخزين البيانات الحساسة في تطبيقات Android والأماكن الآمنة المناسبة لذلك.
الحل
المشكلة: التطبيق يستخدم SharedPreferences لتخزين بيانات حساسة وهي غير آمنة ويمكن الوصول إليها بسهولة على الأجهزة التي تمتلك صلاحية root.
الحل: استخدام Android Keystore System لتخزين البيانات الحساسة بشكل آمن:
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
// إنشاء مفتاح تشفير إذا لم يكن موجوداً
if (!keyStore.containsAlias("app_key")) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
"app_key", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(true);
keyGenerator.init(builder.build());
keyGenerator.generateKey();
}
// تشفير البيانات قبل تخزينها
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKey key = (SecretKey) keyStore.getKey("app_key", null);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedUsername = cipher.doFinal(username.getBytes());
byte[] encryptedPassword = cipher.doFinal(password.getBytes());
// تخزين البيانات المشفرة في SharedPreferences
SharedPreferences prefs = getSharedPreferences("user_data", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("username", Base64.encodeToString(encryptedUsername, Base64.DEFAULT));
editor.putString("password", Base64.encodeToString(encryptedPassword, Base64.DEFAULT));
editor.putString("iv", Base64.encodeToString(cipher.getIV(), Base64.DEFAULT));
editor.apply();
Log.d("App", "تم حفظ بيانات الاعتماد بشكل آمن");
} catch (Exception e) {
Log.e("App", "خطأ في حفظ البيانات: " + e.getMessage());
}
}
التحدي الثاني: ثغرة Certificate Pinning
صعباكتشف أن التطبيق لا يستخدم Certificate Pinning مما يجعله عرضة لهجمات Man-in-the-Middle. كيف يمكنك تنفيذ هذه الحماية؟
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.bankapp.com/login")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
// معالجة الاستجابة
}
@Override
public void onFailure(Call call, IOException e) {
// معالجة الفشل
}
});
تلميح
ابحث عن تقنيات Certificate Pinning في Android وكيفية تنفيذها باستخدام OkHttp أو مكتبات أخرى.
الحل
المشكلة: التطبيق لا يستخدم Certificate Pinning مما يسمح لهجمات Man-in-the-Middle.
الحل: تنفيذ Certificate Pinning باستخدام OkHttp:
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("api.bankapp.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.add("api.bankapp.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
Request request = new Request.Builder()
.url("https://api.bankapp.com/login")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
// معالجة الاستجابة
}
@Override
public void onFailure(Call call, IOException e) {
// معالجة الفشل
}
});
ملاحظة: يجب استبدال البصمات (sha256) ببصمات الشهادات الفعلية لخادمك.
التحدي الثالث: ثغرة Exporting Components
متوسطاكتشف أن التطبيق يصدر Activities و Services بدون قيود مناسبة، مما يسمح للتطبيقات الأخرى بالوصول إليها. كيف يمكنك تأمين هذه المكونات؟
<activity
android:name=".LoginActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="bankapp" />
</intent-filter>
</activity>
<service
android:name=".PaymentService"
android:exported="true" />
تلميح
ابحث عن مفهوم exported components في Android وكيفية تأمينها باستخدام الأذونات والتحقق من التطبيق المستدعي.
الحل
المشكلة: المكونات مصدرة بدون قيود مما يسمح لأي تطبيق بالوصول إليها.
الحل: تأمين المكونات باستخدام الأذونات والتحقق من التطبيق المستدعي:
<permission
android:name="com.bankapp.permission.ACCESS_PAYMENT_SERVICE"
android:protectionLevel="signature" />
<activity
android:name=".LoginActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="bankapp" />
</intent-filter>
</activity>
<service
android:name=".PaymentService"
android:exported="true"
android:permission="com.bankapp.permission.ACCESS_PAYMENT_SERVICE" />
مع إضافة التحقق البرمجي في المكونات:
if (getCallingPackage() != null && !isValidCaller(getCallingPackage())) {
finish(); // أو stopSelf() للـ Service
return;
}
private boolean isValidCaller(String packageName) {
// التحقق من أن التطبيق المستدعي موثوق
return "com.trusted.app".equals(packageName);
}