WebViews - تضمين ملف غير آمن

فئة OWASP: MASVS-STORAGE: مساحة التخزين

نظرة عامة

يتناول هذا المستند عدة مشاكل متعلقة بتضمين الملفات تتشارك في إجراءات التخفيف المشابهة. تتعلّق هذه المشاكل بالثغرات الأمنية الناتجة عن الوصول إلى الملفات داخل مكوّنات WebView، وتتراوح بين WebSettings الخطير الذي يسمح بالوصول إلى الملفات أو تفعيل JavaScript، وطريقة WebKit التي تنشئ طلب اختيار ملف. سيكون هذا المستند مفيدًا إذا كنت تبحث عن إرشادات حول معالجة المشاكل في WebView الناتجة عن استخدام المخطط file://، والوصول غير المحدود إلى الملفات المحلية، وهجمات Cross-Site Scripting.

على وجه التحديد، يتناول هذا المستند المواضيع التالية:

  • WebSettings هي فئة تحتوي على طرق تدير حالات الإعدادات الخاصة بـ WebViews. ويمكن أن تتيح هذه الطرق فتح WebViews لهجمات مختلفة سيتم توضيحها لاحقًا. في هذا المستند، سنتناول الطرق المتعلّقة بكيفية الوصول إلى الملفات والإعداد الذي يسمح بتنفيذ JavaScript:
  • يمكن استخدام الطرق setAllowFileAccess وsetAllowFileAccessFromFileURLs وsetAllowUniversalAccessFromFileURLs لمنح إذن الوصول إلى الملفات المحلية باستخدام عنوان URL لمخطط الملفات (file://)، ولكن يمكن أن تستغلها النصوص البرمجية الضارة للوصول إلى أي ملفات محلية يمكن للتطبيق الوصول إليها، مثل المجلد /data/ الخاص بها. لهذا السبب، تم تصنيف هذه الطرق على أنّها غير آمنة وتم إيقافها نهائيًا في الإصدار 30 من واجهة برمجة التطبيقات، واستُبدلت بطرق بديلة أكثر أمانًا، مثل WebViewAssetLoader.
  • يمكن استخدام طريقة setJavascriptEnabled لتفعيل تنفيذ JavaScript في WebViews. وهذا يجعل التطبيقات معرّضة لخطر إدخال النصوص البرمجية على المواقع الإلكترونية (XSS) المستندة إلى الملفات. ويزداد هذا الخطر عند ضبطها للسماح بتحميل الملفات المحلية أو محتوى الويب غير الموثوق به الذي قد يحتوي على رمز قابل للتنفيذ، أو ضبطها للسماح بالوصول إلى الملفات التي يمكن إنشاؤها أو تغييرها من خلال مصادر خارجية، أو السماح لمكوّنات WebView بتنفيذ JavaScript، ما يعرّض المستخدمين وبياناتهم للخطر.
  • WebChromeClient.onShowFileChooser هي طريقة تنتمي إلى حزمة android.webkit التي توفّر أدوات لتصفُّح الويب. يمكن استخدام هذا الإجراء للسماح للمستخدمين باختيار الملفات داخل WebView. ومع ذلك، يمكن إساءة استخدام هذه الميزة لأنّ WebViews لا تفرض قيودًا على الملف الذي يتم اختياره.

التأثير

يمكن أن يعتمد تأثير تضمين الملفات على إعدادات WebSettings التي تم ضبطها في WebView. يمكن أن تسمح أذونات الملفات الواسعة النطاق للمهاجمين بالوصول إلى الملفات المحلية وسرقة البيانات الحسّاسة أو معلومات التعريف الشخصية أو بيانات التطبيقات الخاصة. قد يؤدي تفعيل تنفيذ JavaScript إلى السماح للمهاجمين بتشغيل JavaScript داخل WebView أو على جهاز المستخدم. قد تؤدي الملفات التي يتم اختيارها باستخدام طريقة onShowFileChooser إلى تعريض أمان المستخدم للخطر، إذ لا يمكن للطريقة أو WebView التأكّد من أنّ مصدر الملف موثوق به.

الخطر: الوصول الخطير إلى الملفات من خلال file://

يمكن أن يؤدي تفعيل setAllowFileAccess وsetAllowFileAccessFromFileURLs وsetAllowUniversalAccessFromFileURLs إلى السماح لطلبات WebView وملفات Intent الضارة التي تتضمّن سياق file:// بالوصول إلى ملفات محلية عشوائية، بما في ذلك ملفات تعريف الارتباط في WebView وبيانات التطبيق الخاصة. بالإضافة إلى ذلك، يمكن أن يسمح استخدام طريقة onShowFileChooser للمستخدمين باختيار الملفات وتنزيلها من مصادر غير موثوق بها.

ويمكن أن تؤدي كل هذه الطرق إلى استخراج معلومات التعريف الشخصية أو بيانات اعتماد تسجيل الدخول أو غيرها من البيانات الحساسة، وذلك حسب إعدادات التطبيق.

إجراءات التخفيف

التحقّق من صحة عناوين URL للملفات

إذا كان تطبيقك يتطلّب الوصول إلى الملفات من خلال عناوين URL file://، من المهم إضافة عناوين URL معيّنة فقط إلى القائمة المسموح بها، وتجنُّب الأخطاء الشائعة.

استخدام WebViewAssetLoader

استخدِم WebViewAssetLoader بدلاً من الطرق المذكورة. تستخدم هذه الطريقة المخطط http(s)//: بدلاً من المخطط file:// للوصول إلى مواد عرض نظام الملفات المحلية، وهي ليست عرضة للهجوم الموصوف.

Kotlin

val assetLoader: WebViewAssetLoader = Builder()
  .addPathHandler("/assets/", AssetsPathHandler(this))
  .build()

webView.setWebViewClient(object : WebViewClientCompat() {
  @RequiresApi(21)
  override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest): WebResourceResponse {
    return assetLoader.shouldInterceptRequest(request.url)
  }

  @Suppress("deprecation") // for API < 21
  override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse {
    return assetLoader.shouldInterceptRequest(Uri.parse(url))
  }
})

val webViewSettings: WebSettings = webView.getSettings()
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.allowFileAccessFromFileURLs = false
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.allowUniversalAccessFromFileURLs = false
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.allowFileAccess = false
webViewSettings.allowContentAccess = false

// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webView.loadUrl("https://appassets.androidplatform.net/assets/www/index.html")

Java

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
         .addPathHandler("/assets/", new AssetsPathHandler(this))
         .build();

webView.setWebViewClient(new WebViewClientCompat() {
    @Override
    @RequiresApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        return assetLoader.shouldInterceptRequest(request.getUrl());
    }

    @Override
    @SuppressWarnings("deprecation") // for API < 21
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        return assetLoader.shouldInterceptRequest(Uri.parse(url));
    }
});

WebSettings webViewSettings = webView.getSettings();
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.setAllowFileAccessFromFileURLs(false);
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.setAllowUniversalAccessFromFileURLs(false);
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.setAllowFileAccess(false);
webViewSettings.setAllowContentAccess(false);

// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webview.loadUrl("https://appassets.androidplatform.net/assets/www/index.html");

إيقاف طرق WebSettings الخطيرة

يتم ضبط قيم الطرق setAllowFileAccess() وsetAllowFileAccessFromFileURLs() وsetAllowUniversalAccessFromFileURLs() تلقائيًا على TRUE في المستوى 29 من واجهة برمجة التطبيقات والمستويات الأقل، وعلى FALSE في المستوى 30 من واجهة برمجة التطبيقات والمستويات الأعلى.

إذا كانت هناك حاجة إلى ضبط WebSettings أخرى، من الأفضل إيقاف هذه الطرق بشكلٍ صريح، خاصةً بالنسبة إلى التطبيقات التي تستهدف مستويات أقل من 29 أو تساويها.


المخاطرة: File-Based XSS

يؤدي ضبط طريقة setJavacriptEnabled على TRUE إلى السماح بتنفيذ JavaScript داخل WebView، وعند دمجه مع إذن الوصول إلى الملفات كما هو موضّح سابقًا، يصبح من الممكن تنفيذ هجمات البرمجة النصية على المواقع الإلكترونية (XSS) المستندة إلى الملفات من خلال تنفيذ الرمز البرمجي داخل ملفات عشوائية أو مواقع إلكترونية ضارة يتم فتحها داخل WebView.

إجراءات التخفيف

منع مكوّنات WebView من تحميل الملفات المحلية

كما هو الحال مع المخاطر السابقة، يمكن تجنُّب الثغرة الأمنية File-based XSS إذا تم ضبط setAllowFileAccess() وsetAllowFileAccessFromFileURLs() وsetAllowUniversalAccessFromFileURLs() على FALSE.

منع مكوّنات WebView من تنفيذ JavaScript

اضبط الطريقة setJavascriptEnabled على FALSE حتى لا يمكن تنفيذ JavaScript داخل WebViews.

التأكّد من أنّ مكوّنات WebView لا تحمِّل محتوى غير موثوق به

في بعض الأحيان، يكون تفعيل هذه الإعدادات ضروريًا في مكوّنات WebView. في هذه الحالة، من المهم التأكّد من أنّه يتم تحميل المحتوى الموثوق به فقط. يُعدّ حصر تنفيذ JavaScript على ما تتحكّم فيه فقط وعدم السماح بتنفيذ JavaScript بشكل عشوائي إحدى الطرق الجيدة لضمان موثوقية المحتوى. في ما عدا ذلك، يضمن منع تحميل زيارات نصية عادية ألا تتمكّن مكوّنات WebView التي تتضمّن إعدادات خطيرة من تحميل عناوين URL عبر HTTP على الأقل. ويمكن إجراء ذلك من خلال ملف البيان عن طريق ضبط android:usesCleartextTraffic على False، أو عن طريق ضبط Network Security Config يمنع زيارات HTTP.


المراجع