Asosiy matnga o'tish
Blog

Mobil

Deep link va eksport qilingan komponentlar: Android va iOS ilovaning ochiq eshiklari

Eksport qilingan activity, service, receiver va provider'lar hamda deep link'lar ilovaga tashqaridan kirish yo'li. Ularni qanday tekshirish va yopish kerak.

· 10 daq. o'qish

Foto: Berna Gaitán Otarán, CC BY-SA 4.0 · Wikimedia Commons

Mobil ilovaning hujum yuzasi faqat uning server API'si bilan cheklanmaydi. Android'da har bir ilova boshqa ilovalar bilan intent orqali gaplasha oladi, iOS'da esa URL sxemalari va universal link'lar orqali ochiladi. Bu mexanizmlar qulay: SMS'dagi havola to'g'ridan-to'g'ri to'lov sahifasini ochadi, brauzerdagi tugma ilovaga o'tkazadi. Lekin har bir shunday "kirish eshigi" — tashqi, ishonchsiz ma'lumot qabul qiladigan joy. Ekspertizada mobil ilova tekshirilganda aynan shu eshiklar ro'yxati olinadi va har biri sinab ko'riladi.

Bu maqolada Android'ning eksport qilingan komponentlari, deep link'lar, App Links tasdiqlash va iOS universal link'larini ko'rib chiqamiz: muammo nimada, qanday o'zingiz tekshirasiz va qanday yopasiz.

Muammo nimada

Android ilovasi to'rt turdagi komponentdan tuziladi:

  • Activity — ekran;
  • Service — fon xizmati;
  • Broadcast receiver — tizim yoki boshqa ilovalardan keladigan xabarlarni qabul qiluvchi;
  • Content provider — ma'lumotlarni boshqa ilovalarga URI orqali beruvchi qatlam.

Har bir komponent AndroidManifest.xml faylida e'lon qilinadi va android:exported atributi bilan belgilanadi. Agar exported="true" bo'lsa, qurilmadagi istalgan boshqa ilova (shu jumladan zararli ilova) uni to'g'ridan-to'g'ri chaqira oladi. Komponent ichidagi kod esa ko'pincha "meni faqat o'z ilovam chaqiradi" degan farazda yozilgan bo'ladi.

Tipik xatolar:

  1. Ichki ekran eksport qilingan. Masalan, SettingsActivity yoki PinChangeActivity login'dan keyin ochilishi kerak, lekin eksport qilingani uchun uni tashqaridan, autentifikatsiyani chetlab ochish mumkin.
  2. Intent ma'lumotiga ko'r-ko'rona ishonish. Activity intent'dan url parametrini olib, uni WebView'da ochadi yoki amount, account qiymatlarini to'g'ridan-to'g'ri to'lov formasiga qo'yadi. Bu intent spoofing deb ataladi: tashqi ilova soxta, lekin ishonchli ko'rinadigan so'rov yuboradi.
  3. Himoyasiz content provider. Provider eksport qilingan va ruxsat (permission) talab qilmaydi — boshqa ilova content:// URI orqali foydalanuvchi ma'lumotlarini o'qiydi. Fayl beradigan provider'larda ../ orqali path traversal ham uchraydi.
  4. Broadcast receiver har qanday xabarni qabul qiladi. Masalan, "sessiyani yangilash" yoki "sinxronlash" buyrug'ini kim yuborganini tekshirmaydi.
  5. Deep link parametrlari tekshirilmaydi. myapp://open?url=... havolasi ilova ichidagi WebView'da istalgan saytni ochadi yoki myapp://transfer?to=...&sum=... bevosita amal bajaradi.

Android 12 (API 31) dan boshlab intent-filter'i bor har bir komponent uchun android:exported qiymatini aniq yozish majburiy. Bu yaxshi o'zgarish, lekin muammoni hal qilmaydi: dasturchilar ko'pincha build xatosini yo'qotish uchun hamma joyga true yozib qo'yishadi.

Deep link ikki xil bo'ladi:

  • Custom URL sxema (myapp://...). Uni istalgan ilova o'zida ro'yxatdan o'tkazishi mumkin. Agar ikkita ilova bir xil sxemani e'lon qilsa, tizim foydalanuvchidan tanlashni so'raydi yoki boshqasini ochib yuboradi. Demak, bunday havola orqali maxfiy ma'lumot (masalan, OAuth kodi yoki tasdiqlash tokeni) uzatish xavfli — uni boshqa ilova ushlab olishi mumkin.
  • Android App Links / iOS Universal Links (https://example.uz/...). Domen egasi o'z serverida faylni joylashtirib, qaysi ilova bu havolalarni ochishi mumkinligini tasdiqlaydi. Boshqa ilova bu domenni "egallab" ololmaydi.

OAuth uchun custom sxema ishlatilsa, PKCE (RFC 7636) majburiy bo'lishi kerak — bu ushlab olingan kodni yolg'iz o'zi ishlatib bo'lmaydigan qiladi.

Nega bu ekspertiza uchun muhim

Mobil ilova ekspertizasi OWASP MASVS va MASTG metodologiyasiga tayanadi. MASVS'ning PLATFORM guruhi ilova platforma bilan xavfsiz o'zaro aloqa qilishini talab qiladi: IPC mexanizmlari faqat zarur bo'lganda ochiladi, tashqaridan kelgan ma'lumotlar tekshiriladi. OWASP Mobile Top 10 (2024) bo'yicha bu M4 (Insufficient Input/Output Validation) va M8 (Security Misconfiguration) toifalariga, ba'zan M3 (Insecure Authentication/Authorization) ga tushadi — agar eksport qilingan ekran autentifikatsiyani chetlab o'tishga imkon bersa.

Ekspert APK'ni ochib, manifest'dan barcha eksport qilingan komponentlarni chiqaradi va har birini qo'lda chaqirib ko'radi. Bu avtomatlashtirilgan vositalar ham darhol ko'rsatadigan topilma, shuning uchun uni ekspertizadan oldin yopish oson va foydali.

O'zingiz qanday tekshirasiz

1. Manifest'ni oching

Release APK'ni apktool bilan oching va eksport qilinganlarni qidiring:

apktool d app-release.apk -o app_src
grep -n 'exported="true"' app_src/AndroidManifest.xml
grep -n '<intent-filter' app_src/AndroidManifest.xml

E'tibor bering: tekshirish kerak bo'lgan narsa — yakuniy, birlashtirilgan (merged) manifest. Kutubxonalar o'z komponentlarini qo'shadi va ular ham sizning ilovangiz nomidan ochiq bo'ladi. Android Studio'da Merged Manifest yorlig'i yoki APK Analyzer buni ko'rsatadi.

Har bir eksport qilingan komponent uchun bitta savol bering: "Buni boshqa ilova chaqirishi kerakmi?" Javob "yo'q" bo'lsa — exported="false".

2. Komponentlarni tashqaridan chaqiring

Test qurilmada adb orqali:

# Activity'ni to'g'ridan-to'g'ri ochish
adb shell am start -n uz.example.app/.ui.PinChangeActivity

# Deep link'ni sinash
adb shell am start -a android.intent.action.VIEW \
  -d "myapp://open?url=https://evil.example.com"

# Broadcast yuborish
adb shell am broadcast -a uz.example.app.SYNC_NOW

# Content provider'dan o'qish
adb shell content query --uri content://uz.example.app.provider/users

Kutilgan natija: ichki ekranlar ochilmaydi yoki login'ga qaytaradi; deep link begona domenni ochmaydi; broadcast e'tiborsiz qoladi; provider ruxsat xatosini qaytaradi.

Kengroq sinov uchun drozer kabi vositalar mavjud — ular eksport qilingan komponentlarni avtomatik ro'yxatlaydi va chaqiradi.

adb shell pm get-app-links uz.example.app

Domen yonida verified bo'lishi kerak. Agar none yoki legacy_failure bo'lsa, assetlinks.json fayli noto'g'ri yoki topilmagan.

curl -i https://example.uz/.well-known/assetlinks.json

Javob 200, Content-Type: application/json, redirect'siz bo'lishi va ichida release imzo sertifikatining SHA-256 xeshi turishi kerak.

4. iOS'ni tekshiring

IPA ichidagi Info.plist faylida CFBundleURLTypes (custom sxemalar) va entitlements'da com.apple.developer.associated-domains ni ko'ring. Serverdagi fayl:

curl -i https://example.uz/.well-known/apple-app-site-association

Simulyatorda havolani ochib ko'rish:

xcrun simctl openurl booted "myapp://open?url=https://evil.example.com"

Qanday yopiladi

Android: manifest

Ichki komponentlar yopiq bo'lsin:

<activity
    android:name=".ui.PinChangeActivity"
    android:exported="false" />

<receiver
    android:name=".sync.SyncReceiver"
    android:exported="false" />

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

Agar komponent haqiqatan ham faqat o'z ilovalaringiz oilasi uchun ochiq bo'lishi kerak bo'lsa, signature darajasidagi ruxsat ishlating:

<permission
    android:name="uz.example.permission.INTERNAL"
    android:protectionLevel="signature" />

<service
    android:name=".api.PartnerService"
    android:exported="true"
    android:permission="uz.example.permission.INTERNAL" />

Fayl ulashish uchun o'z provider'ingizni yozmang — FileProvider va file_paths.xml da faqat aniq papkani ko'rsating (butun ichki xotirani emas).

Deep link activity'sini faqat tasdiqlangan domenga bog'lang:

<activity android:name=".DeepLinkActivity" android:exported="true">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="https"
              android:host="example.uz"
              android:pathPrefix="/app" />
    </intent-filter>
</activity>

Serverda /.well-known/assetlinks.json:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "uz.example.app",
    "sha256_cert_fingerprints": ["AB:CD:...:EF"]
  }
}]

Google Play App Signing ishlatilsa, xeshni Play Console'dagi ilova imzo kalitidan oling. nginx'da bu fayl to'g'ri tur bilan berilishini tekshiring:

location = /.well-known/assetlinks.json {
    default_type application/json;
}

Har qanday kirish — ishonchsiz kirish

Manifest to'g'ri bo'lsa ham, deep link ichidagi parametrlar tekshirilishi shart. Kotlin misoli:

val uri = intent.data ?: return finish()
if (uri.scheme != "https" || uri.host != "example.uz") return finish()

val target = uri.getQueryParameter("url")
val allowed = setOf("example.uz", "pay.example.uz")
val host = target?.let { Uri.parse(it).host }
if (host == null || host !in allowed) return finish()

Qoidalar:

  • Deep link hech qachon amalni bevosita bajarmasin. U faqat ekranni ochadi, foydalanuvchi esa amalni o'zi tasdiqlaydi (masalan, to'lov summasini ko'radi va PIN kiritadi).
  • Deep link orqali ochilgan ekran ham sessiya va huquqlarni tekshirsin.
  • Tashqi URL'ni WebView'da ochishdan oldin domen allowlist'dan o'tkazilsin.
  • PendingIntent yaratganda FLAG_IMMUTABLE ishlating va bo'sh (implicit) intent bermang.
  • Intent'dan kelgan qiymat bilan startActivity() qilish (intent redirection) — faqat ichki, aniq komponentlarga.

Flutter

Flutter'da deep link'lar odatda app_links paketi yoki go_router orqali qayta ishlanadi. Manifest qismi yuqoridagidek bo'ladi, Dart tomonda esa marshrutni allowlist bilan tekshiring:

GoRoute(
  path: '/app/payment/:id',
  redirect: (context, state) {
    final loggedIn = auth.isLoggedIn;
    if (!loggedIn) return '/login?next=${state.uri.path}';
    return null;
  },
  builder: (context, state) =>
      PaymentScreen(id: state.pathParameters['id']!),
),

Marshrut parametrlari faqat identifikator bo'lsin; summa, hisob raqami va boshqa muhim qiymatlar server'dan identifikator bo'yicha olinadi.

Xcode'da Associated Domains qo'shing: applinks:example.uz. Serverdagi apple-app-site-association fayli (kengaytmasiz, JSON, redirect'siz):

{
  "applinks": {
    "details": [{
      "appIDs": ["TEAMID.uz.example.app"],
      "components": [{ "/": "/app/*" }]
    }]
  }
}

Custom sxemani (myapp://) iloji boricha universal link bilan almashtiring. Qoldirilsa, application(_:open:options:) yoki SwiftUI'dagi onOpenURL ichida xuddi Android'dagidek host, yo'l va parametrlarni tekshiring. Maxfiy kodlarni custom sxema orqali uzatmang.

Qisqa checklist

  • Merged manifest'dagi har bir exported="true" asoslangan; qolganlari false.
  • Kutubxonalar qo'shgan komponentlar ham ko'rib chiqilgan.
  • Content provider'lar eksport qilinmagan yoki signature ruxsati bilan himoyalangan; fayllar FileProvider orqali.
  • Broadcast receiver'lar tashqi xabarga javob bermaydi.
  • Deep link'lar https App Links / Universal Links; assetlinks.json va apple-app-site-association serverda to'g'ri.
  • pm get-app-links natijasi verified.
  • Deep link parametrlari allowlist bilan tekshiriladi; amal bevosita bajarilmaydi.
  • Deep link orqali ochilgan ekran sessiyani tekshiradi.
  • OAuth custom sxema bilan bo'lsa — PKCE yoqilgan.
  • PendingIntent lar FLAG_IMMUTABLE.
  • adb am start, am broadcast, content query bilan qo'lda sinov o'tkazilgan.

Xulosa

Eksport qilingan komponentlar va deep link'lar ilovaning eng ko'p e'tibordan chetda qoladigan qismi: ular build vaqtida bitta atribut bilan ochiladi va kod ko'rib chiqishda ko'rinmaydi. Ekspert esa ularni birinchi qadamda ro'yxatlaydi. Manifest'ni tozalash, App Links / Universal Links'ga o'tish va har bir tashqi kirishni ishonchsiz deb qabul qilish — bu topilmalarni yopishning eng to'g'ri yo'li. Shu mavzuga yaqin maqolalar: WebView xavfsizligi va mobil ilova ekspertizasida nimalar tekshiriladi.

Ilovangizdagi ochiq eshiklar ro'yxatini ekspertizadan oldin ko'rmoqchi bo'lsangiz, skanerlash uchun ariza qoldiring. Claude AI agenti manifest va kodni tez ko'rib chiqadi, mutaxassisimiz esa har bir topilmani qurilmada tasdiqlaydi va yopishda yordam beradi.