WebView – การรวมไฟล์ที่ไม่ปลอดภัย

หมวดหมู่ OWASP: MASVS-STORAGE: พื้นที่เก็บข้อมูล

ภาพรวม

เอกสารนี้ครอบคลุมปัญหาหลายประการที่เกี่ยวข้องกับการรวมไฟล์ซึ่งใช้วิธีแก้ไขที่คล้ายกัน ปัญหาเหล่านี้มุ่งเน้นที่ช่องโหว่ที่เกิดจากสิทธิ์เข้าถึงไฟล์ภายใน WebView และครอบคลุมตั้งแต่ WebSettings ที่อันตรายซึ่งอนุญาตให้เข้าถึงไฟล์หรือเปิดใช้ JavaScript ไปจนถึงเมธอด WebKit ที่สร้างคำขอการเลือกไฟล์ เอกสารนี้ควรมีประโยชน์หากคุณกำลังมองหาคำแนะนำในการแก้ไขปัญหาภายใน WebView ที่เกิดจากการใช้รูปแบบ file:// การเข้าถึงไฟล์ในเครื่องแบบไม่จำกัด และ Cross-Site Scripting

กล่าวโดยละเอียดคือ เอกสารนี้ครอบคลุมหัวข้อต่อไปนี้

  • WebSettings คือคลาสที่��ีเมธอดซึ่งจัดการสถานะการตั้งค่าสําหรับ WebView วิธีการเหล่านี้อาจเปิดโอกาสให้เกิดการโจมตี WebView ในรูปแบบต่างๆ ซึ่งจะระบุไว้ภายหลัง ในเอกสารนี้ เราจะดูวิธีการต่างๆ ที่เกี่ยวข้องกับวิธีเข้าถึงไฟล์และการตั้งค่าที่อนุญาตให้เรียกใช้ JavaScript
  • คุณสามารถใช้เมธอด setAllowFileAccess, setAllowFileAccessFromFileURLs และ setAllowUniversalAccessFromFileURLs เพื่อมอบสิทธิ์เข้าถึงไฟล์ในเครื่องโดยใช้ URL รูปแบบไฟล์ (file://) อย่างไรก็ตาม สคริปต์ที่เป็นอันตรายอาจใช้ประโยชน์จากเมธอดเหล่านี้เพื่อเข้าถึงไฟล์ในเครื่องที่แอปพลิเคชันเข้าถึงได้ อย่างเช่นโฟลเดอร์ /data/ ของตนเอง ด้วยเหตุนี้ ระบบจึงแจ้งว่าวิธีการเหล่านี้ไม่ปลอดภัยและเลิกใช้งานใน API 30 แทนที่จะใช้วิธีการอื่นที่ปลอดภัยกว่า เช่น WebViewAssetLoader
  • คุณสามารถใช้เมธอด setJavascriptEnabled เพื่อเปิดใช้การเรียกใช้ JavaScript ภายใน WebView ซึ่งทำให้แอปพลิเคชันมีความเสี่ยงต่อ XSS แบบไฟล์ โดยเฉพาะอย่างยิ่งเมื่อกำหนดค่าให้อนุญาตการโหลดไฟล์ในเครื่องหรือเนื้อหาเว็บที่ไม่น่าเชื่อถือซึ่งอาจมีโค้ดที่เรียกใช้ได้ กำหนดค่าให้อนุญาตการเข้าถึงไฟล์ที่แหล่งที่มาภายนอกสร้างหรือเปลี่ยนแปลงได้ หรืออนุญาตให้ WebView เรียกใช้ JavaScript ผู้ใช้และข้อมูลของผู้ใช้จะตกอยู่ในความเสี่ยง
  • WebChromeClient.onShowFileChooser เป็นเมธอดที่อยู่ในแพ็กเกจ android.webkit ซึ่งให้เครื่องมือการท่องเว็บ เมธอดนี้สามารถใช้เพื่ออนุญาตให้ผู้ใช้เลือกไฟล์ภายใน WebView อย่างไรก็ตาม ฟีเจอร์นี้อาจถูกละเมิดได้เนื่องจาก WebView ไม่ได้บังคับใช้ข้อจำกัดเกี่ยวกับไฟล์ที่เลือก

ผลกระทบ

ผลของการรวมไฟล์อาจขึ้นอยู่กับ WebSettings ที่กําหนดค่าใน WebView สิทธิ์เข้าถึงไฟล์ที่กว้างเกินไปอาจทำให้ผู้โจมตีเข้าถึงไฟล์ในเครื่องและขโมยข้อมูลที่ละเอียดอ่อน, PII (ข้อมูลส่วนบุคคลที่ระบุตัวบุคคลนั้นได้) หรือข้อมูลแอปส่วนตัวได้ การเปิดใช้การเรียกใช้ JavaScript อาจทำให้ผู้โจมตีเรียกใช้ JavaScript ได้ภายใน WebView หรือในอุปกรณ์ของผู้ใช้ ไฟล์ที่เลือกโดยใช้วิธี onShowFileChooser อาจทำให้ความปลอดภัยของผู้ใช้ลดลง เนื่องจากวิธีหรือ WebView ไม่มีทางตรวจสอบได้ว่าแหล่งที่มาของไฟล์เชื่อถือได้หรือไม่

ความเสี่ยง: การเข้าถึงไฟล์ผ่าน file:// มีความเสี่ยง

การเปิดใช้ setAllowFileAccess, setAllowFileAccessFromFileURLs และ setAllowUniversalAccessFromFileURLs อาจอนุญาตให้ Intent และคำขอ WebView ที่เป็นอันตรายซึ่งมีบริบท file:// เข้าถึงไฟล์ในเครื่องแบบไม่จำกัด รวมถึงคุกกี้ WebView และข้อมูลส่วนตัวของแอป นอกจากนี้ การใช้onShowFileChooserวิธีนี้ยังช่วยให้ผู้ใช้เลือกและดาวน์โหลดไฟล์จากแหล่งที่มาที่ไม่น่าเชื่อถือได้

วิธีการเหล่านี้อาจนำไปสู่การลักลอบนำข้อมูล PII, ข้อมูลเข้าสู่ระบบ หรือข้อมูลที่ละเอียดอ่อนอื่นๆ ออกได้ ทั้งนี้ขึ้นอยู่กับการกำหนดค่าแอปพลิเคชัน

การลดปัญหา

ตรวจสอบ 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 โดยค่าเริ่มต้นใน API ระดับ 29 และต่ำกว่า และ FALSE ใน API ระดับ 30 ขึ้นไป

หากจำเป็นต้องกำหนดค่า WebSettings อื่นๆ วิธีที่ดีที่สุดคือการปิดใช้เมธอดเหล่านี้อย่างชั��เจน โดยเฉพาะสำหรับแอปที่กำหนดเป้าหมายเป็น API ระดับต่ำกว่าหรือเท่ากับ 29


ความเสี่ยง: XSS ตามไฟล์

การตั้งค่าเมธอด setJavacriptEnabled เป็น TRUE จะช่วยให้เรียกใช้ JavaScript ภายใน WebView ได้ และเมื่อใช้ร่วมกับการเปิดใช้การเข้าถึงไฟล์ตามที่ระบุไว้ก่อนหน้านี้ จะทำให้ XSS ตามไฟล์เกิดขึ้นได้ผ่านการเรียกใช้โค้ดภายในไฟล์ที่กำหนดเอง หรือเว็บไซต์ที่เป็นอันตรายที่เปิดภายใน WebView

การลดปัญหา

ป้องกันไม่ให้ WebView โหลดไฟล์ในเครื่อง

เช่นเดียวกับความเสี่ยงก่อนหน้า คุณสามารถหลีกเลี่ยง XSS ที่อิงตามไฟล์ได้หากตั้งค่า setAllowFileAccess(), setAllowFileAccessFromFileURLs() และ setAllowUniversalAccessFromFileURLs() เป็น FALSE

ป้องกันไม่ให้ WebView เรียกใช้ JavaScript

ตั้งค่าเมธอด setJavascriptEnabled เป็น FALSE เพื่อไม่ให้เรียกใช้ JavaScript ภายใน WebView ได้

ตรวจสอบว่า WebView ไม่ได้โหลดเนื้อหาที่ไม่น่าเชื่อถือ

บางครั้งการเปิดใช้การตั้งค่าเหล่านี้ใน WebView เป็นสิ่งที่จำเป็น ในกรณีนี้ คุณจึงต้องตรวจสอบว่าได้โหลดเฉพาะเนื้อหาที่เชื่อถือเท่านั้น การจํากัดการเรียกใช้ JavaScript เฉพาะที่คุณควบคุมได้และไม่อนุญาตให้ใช้ JavaScript ที่ไม่รู้จักเป็นวิธีที่ดีวิธีหนึ่งในการทำให้เนื้อหาเชื่อถือได้ หรือจะป้องกันไม่ให้โหลดการรับส่งข้อมูลแบบข้อความธรรมดาก็ได้ เพื่อให้ WebView ที่มีการตั้งค่าที่เป็นอันตรายไม่สามารถโหลด URL ของ HTTP เป็นอย่างน้อย ซึ่งทำได้ผ่านไฟล์ Manifest โดยตั้งค่า android:usesCleartextTraffic เป็น False หรือตั้งค่า Network Security Config ที่ไม่อนุญาตให้มีการเข้าชมแบบ HTTP


แหล่งข้อมูล