অনিরাপদ ডাউনলোড ম্যানেজার

OWASP বিভাগ: MASVS-নেটওয়ার্ক: নেটওয়ার্ক কমিউনিকেশন

ওভারভিউ

ডাউনলোড ম্যানেজার হল API স্তর 9-এ চালু করা একটি সিস্টেম পরিষেবা। এটি দীর্ঘ-চলমান HTTP ডাউনলোডগুলি পরিচালনা করে এবং অ্যাপ্লিকেশনগুলিকে একটি ব্যাকগ্রাউন্ড টাস্ক হিসাবে ফাইলগুলি ডাউনলোড করার অনুমতি দেয়। এর API HTTP মিথস্ক্রিয়া পরিচালনা করে এবং ব্যর্থতার পরে বা সংযোগ পরিবর্তন এবং সিস্টেম রিবুট জুড়ে ডাউনলোডের পুনরায় চেষ্টা করে।

ডাউনলোডম্যানেজারের নিরাপত্তা সম্পর্কিত দুর্বলতা রয়েছে যা এটিকে অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলিতে ডাউনলোড পরিচালনার জন্য একটি অনিরাপদ পছন্দ করে তোলে।

(1) ডাউনলোড প্রদানকারীতে CVE

2018 সালে, তিনটি CVE পাওয়া গেছে এবং ডাউনলোড প্রদানকারীতে প্যাচ করা হয়েছে। প্রতিটির একটি সারসংক্ষেপ অনুসরণ করে ( প্রযুক্তিগত বিবরণ দেখুন)।

  • ডাউনলোড প্রোভাইডার পারমিশন বাইপাস - কোনও মঞ্জুরি ছাড়াই, একটি দূষিত অ্যাপ ডাউনলোড প্রোভাইডার থেকে সমস্ত এন্ট্রি পুনরুদ্ধার করতে পারে, যার মধ্যে ফাইলের নাম, বিবরণ, শিরোনাম, পাথ, ইউআরএল, সেইসাথে সম্পূর্ণ READ/RITE অনুমতির মতো সম্ভাব্য সংবেদনশীল তথ্য অন্তর্ভুক্ত থাকতে পারে। সব ডাউনলোড করা ফাইল। একটি দূষিত অ্যাপ ব্যাকগ্রাউন্ডে চলতে পারে, সমস্ত ডাউনলোড নিরীক্ষণ করতে পারে এবং তাদের বিষয়বস্তু দূর থেকে ফাঁস করতে পারে, অথবা বৈধ অনুরোধকারীর দ্বারা অ্যাক্সেস করার আগে ফাইলগুলিকে ফ্লাইতে পরিবর্তন করতে পারে। এটি আপডেটগুলি ডাউনলোড করতে অক্ষমতা সহ মূল অ্যাপ্লিকেশনগুলির জন্য ব্যবহারকারীর জন্য পরিষেবা অস্বীকারের কারণ হতে পারে৷
  • ডাউনলোড প্রদানকারী SQL ইনজেকশন - একটি SQL ইনজেকশন দুর্বলতার মাধ্যমে, কোনো অনুমতি ছাড়াই একটি দূষিত অ্যাপ্লিকেশন ডাউনলোড প্রদানকারী থেকে সমস্ত এন্ট্রি পুনরুদ্ধার করতে পারে। এছাড়াও, android.permission.INTERNET এর মতো সীমিত অনুমতি সহ অ্যাপ্লিকেশনগুলি একটি ভিন্ন URI থেকে সমস্ত ডাটাবেস বিষয়বস্তু অ্যাক্সেস করতে পারে। সম্ভাব্য সংবেদনশীল তথ্য যেমন ফাইলের নাম, বিবরণ, শিরোনাম, পাথ, URL পুনরুদ্ধার করা যেতে পারে এবং অনুমতির উপর নির্ভর করে ডাউনলোড করা সামগ্রীতেও অ্যাক্সেস সম্ভব হতে পারে।
  • ডাউনলোড প্রোভাইডার রিকোয়েস্ট হেডার ইনফরমেশন ডিসক্লোজারandroid.permission.INTERNET অনুমতি সহ একটি ক্ষতিকারক অ্যাপ্লিকেশন ডাউনলোড প্রোভাইডার রিকোয়েস্ট হেডার টেবিল থেকে সমস্ত এন্ট্রি পুনরুদ্ধার করতে পারে। এই শিরোনামগুলিতে অন্যান্য অ্যাপ্লিকেশনগুলির মধ্যে Android ব্রাউজার বা Google Chrome থেকে শুরু হওয়া যেকোনো ডাউনলোডের জন্য সেশন কুকিজ বা প্রমাণীকরণ শিরোনামের মতো সংবেদনশীল তথ্য অন্তর্ভুক্ত থাকতে পারে। এটি একজন আক্রমণকারীকে ব্যবহারকারীর ছদ্মবেশ ধারণ করার অনুমতি দিতে পারে যেকোন প্ল্যাটফর্ম থেকে সংবেদনশীল ব্যবহারকারীর ডেটা প্রাপ্ত করা হয়েছিল।

(2) বিপজ্জনক অনুমতি

29-এর থেকে কম API স্তরে ডাউনলোডম্যানেজারের জন্য বিপজ্জনক অনুমতি প্রয়োজন - android.permission.WRITE_EXTERNAL_STORAGE । API স্তর 29 এবং উচ্চতর জন্য, android.permission.WRITE_EXTERNAL_STORAGE অনুমতির প্রয়োজন নেই, তবে URI অবশ্যই অ্যাপ্লিকেশনের মালিকানাধীন ডিরেক্টরিগুলির মধ্যে একটি পাথ বা শীর্ষ-স্তরের "ডাউনলোড" ডিরেক্টরির মধ্যে একটি পথ উল্লেখ করতে হবে৷

(3) Uri.parse()

ডাউনলোড ম্যানেজার অনুরোধ করা ডাউনলোডের অবস্থান পার্স করতে Uri.parse() পদ্ধতির উপর নির্ভর করে। পারফরম্যান্সের স্বার্থে, Uri ক্লাসটি অবিশ্বস্ত ইনপুটে কোনো বৈধতা ছাড়াই সামান্য প্রযোজ্য।

প্রভাব

ডাউনলোড ম্যানেজার ব্যবহার করলে বাহ্যিক সঞ্চয়স্থানে WRITE অনুমতির শোষণের মাধ্যমে দুর্বলতা হতে পারে। যেহেতু android.permission.WRITE_EXTERNAL_STORAGE অনুমতিগুলি বাহ্যিক সঞ্চয়স্থানে বিস্তৃত অ্যাক্সেসের অনুমতি দেয়, তাই আক্রমণকারীর পক্ষে নীরবে ফাইল এবং ডাউনলোডগুলি সংশোধন করা, সম্ভাব্য ক্ষতিকারক অ্যাপগুলি ইনস্টল করা, মূল অ্যাপগুলিতে পরিষেবা অস্বীকার করা বা অ্যাপগুলিকে ক্রাশ করা সম্ভব। ব্যবহারকারীকে ক্ষতিকারক ফাইল ডাউনলোড করার জন্য Uri.parse()-এ যা পাঠানো হয় তা ক্ষতিকারক অভিনেতারাও ব্যবহার করতে পারে।

প্রশমন

ডাউনলোড ম্যানেজার ব্যবহার করার পরিবর্তে, একটি HTTP ক্লায়েন্ট (যেমন Cronet), একটি প্রক্রিয়া নির্ধারণকারী/ব্যবস্থাপক, এবং নেটওয়ার্ক ক্ষতি হলে পুনরায় চেষ্টা নিশ্চিত করার একটি উপায় ব্যবহার করে সরাসরি আপনার অ্যাপে ডাউনলোড সেট আপ করুন। লাইব্রেরির ডকুমেন্টেশনে একটি নমুনা অ্যাপের একটি লিঙ্ক এবং সেইসাথে এটি কীভাবে প্রয়োগ করা যায় তার নির্দেশাবলী অন্তর্ভুক্ত রয়েছে।

আপনার অ্যাপ্লিকেশনের যদি প্রক্রিয়ার সময়সূচী পরিচালনা করার ক্ষমতার প্রয়োজন হয়, ব্যাকগ্রাউন্ডে ডাউনলোডগুলি চালানোর, বা নেটওয়ার্ক হারানোর পরে ডাউনলোড স্থাপনের জন্য পুনরায় চেষ্টা করার জন্য, তাহলে WorkManager এবং ForegroundServices সহ বিবেচনা করুন৷

Cronet ব্যবহার করে ডাউনলোড সেট আপ করার উদাহরণ কোডটি নিম্নরূপ, Cronet codelab থেকে নেওয়া হয়েছে।

কোটলিন

override suspend fun downloadImage(url: String): ImageDownloaderResult {
   val startNanoTime = System.nanoTime()
   return suspendCoroutine {
       cont ->
       val request = engine.newUrlRequestBuilder(url, object: ReadToMemoryCronetCallback() {
       override fun onSucceeded(
           request: UrlRequest,
           info: UrlResponseInfo,
           bodyBytes: ByteArray) {
           cont.resume(ImageDownloaderResult(
               successful = true,
               blob = bodyBytes,
               latency = Duration.ofNanos(System.nanoTime() - startNanoTime),
               wasCached = info.wasCached(),
               downloaderRef = this@CronetImageDownloader))
       }
       override fun onFailed(
           request: UrlRequest,
           info: UrlResponseInfo,
           error: CronetException
       ) {
           Log.w(LOGGER_TAG, "Cronet download failed!", error)
           cont.resume(ImageDownloaderResult(
               successful = false,
               blob = ByteArray(0),
               latency = Duration.ZERO,
               wasCached = info.wasCached(),
               downloaderRef = this@CronetImageDownloader))
       }
   }, executor)
       request.build().start()
   }
}

জাভা

@Override
public CompletableFuture<ImageDownloaderResult> downloadImage(String url) {
    long startNanoTime = System.nanoTime();
    return CompletableFuture.supplyAsync(() -> {
        UrlRequest.Builder requestBuilder = engine.newUrlRequestBuilder(url, new ReadToMemoryCronetCallback() {
            @Override
            public void onSucceeded(UrlRequest request, UrlResponseInfo info, byte[] bodyBytes) {
                return ImageDownloaderResult.builder()
                        .successful(true)
                        .blob(bodyBytes)
                        .latency(Duration.ofNanos(System.nanoTime() - startNanoTime))
                        .wasCached(info.wasCached())
                        .downloaderRef(CronetImageDownloader.this)
                        .build();
            }
            @Override
            public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) {
                Log.w(LOGGER_TAG, "Cronet download failed!", error);
                return ImageDownloaderResult.builder()
                        .successful(false)
                        .blob(new byte[0])
                        .latency(Duration.ZERO)
                        .wasCached(info.wasCached())
                        .downloaderRef(CronetImageDownloader.this)
                        .build();
            }
        }, executor);
        UrlRequest urlRequest = requestBuilder.build();
        urlRequest.start();
        return urlRequest.getResult();
    });
}

সম্পদ