Exposing the Android file system to WebViews is security-sensitive.
Granting file access to WebViews, particularly through the file://
scheme, introduces a risk of local file inclusion vulnerabilities.
The severity of this risk depends heavily on the specific WebSettings
configured. Overly permissive settings can allow malicious scripts
to access a wide range of local files, potentially exposing sensitive data such as Personally Identifiable Information (PII) or private application
data, leading to data breaches and other security compromises.
Ask Yourself Whether
- You open files that may be created or altered by external sources.
- You open arbitrary URLs from external sources.
There is a risk if you answered yes to any of these questions.
Recommended Secure Coding Practices
Avoid opening file://
URLs from external sources in WebView components. If your application accepts arbitrary URLs from external
sources, do not enable this functionality. Instead, utilize androidx.webkit.WebViewAssetLoader
to access files, including assets and
resources, via http(s)://
schemes.
For enhanced security, ensure that the options to load file://
URLs are explicitly set to false.
Sensitive Code Example
AndroidView(
factory = { context ->
WebView(context).apply {
webViewClient = WebViewClient()
settings.apply {
allowFileAccess = true // Sensitive
allowFileAccessFromFileURLs = true // Sensitive
allowUniversalAccessFromFileURLs = true // Sensitive
allowContentAccess = true // Sensitive
}
loadUrl("file:///android_asset/example.html")
}
}
)
Compliant Solution
AndroidView(
factory = { context ->
val webView = WebView(context)
val assetLoader = WebViewAssetLoader.Builder()
.addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(context))
.build()
webView.webViewClient = object : WebViewClient() {
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest): WebResourceResponse? {
return assetLoader.shouldInterceptRequest(request.url)
}
@Suppress("deprecation")
override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse? {
return assetLoader.shouldInterceptRequest(Uri.parse(url))
}
}
webView.settings.apply {
allowFileAccess = false
allowFileAccessFromFileURLs = false
allowUniversalAccessFromFileURLs = false
allowContentAccess = false
}
webView.loadUrl("https://appassets.androidplatform.net/assets/example.html")
webView
}
)
The compliant solution uses WebViewAssetLoader
to load local files instead of directly accessing them via file://
URLs.
This approach serves assets over a secure https://appassets.androidplatform.net
URL,
effectively isolating the WebView from the local file system.
The file access settings are disabled by default in modern Android versions. To prevent possible security issues in
Build.VERSION_CODES.Q
and earlier, it is still recommended to explicitly set those values to false.
See