หมวดหมู่ OWASP: MASVS-STORAGE: 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
อาจทําให้เจตนามุ่งร้ายและคําขอ WebView
ที่มีบริบท file://
เข้าถึงไฟล์ในเครื่องโดยพลการได้ ซึ่งรวมถึง
คุกกี้ WebView และข้อมูลส่วนตัวของแอป นอกจากนี้ การใช้onShowFileChooser
method ยังช่วยให้ผู้ใช้เลือกและดาวน์โหลดไฟล์จากแหล่งที่มาที่ไม่น่าเชื่อถือได้ด้วย
วิธีการเหล่านี้อาจนำไปสู่การกรองข้อมูล PII, ข้อมูลเข้าสู่ระบบ หรือข้อมูลที่ละเอียดอ่อนอื่นๆ ออก ทั้งนี้ขึ้นอยู่กับการกำหนดค่าแอปพลิเคชัน
การลดปัญหา
ตรวจสอบ URL ของไฟล์
หากแอปของคุณต้องเข้าถึงไฟล์ผ่าน file://
URL คุณควรอนุญาตเฉพาะ 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
ความเสี่ยง: File-Based 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
แหล่งข้อมูล
- หน้าเอกสารอ้างอิง API ของ setAllowUniversalAccessFromFileURLs
- หน้าเอกสารอ้างอิง API ของ setAllowFileAccessFromFileURLs
- หน้าเอกสารอ้างอิง WebViewAssetLoader API
- เอกสารประกอบของ CodeQL
- บล็อกที่มีการรักษาความปลอดภัยมากเกินไป
- หน้าอ้างอิง onShowFileChooser