หมวดหมู่ 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
แหล่งข้อมูล
- หน้าอ้างอิง setAllowUniversalAccessFromFileURLs API
- หน้าอ้างอิง setAllowFileAccessFromFileURLs API
- หน้าอ้างอิง WebViewAssetLoader API
- เอกสารประกอบ CodeQL
- บล็อกที่มีการรักษาความปลอดภัยมากเกินไป
- หน้าอ้างอิง onShowFileChooser