Danh mục OWASP: MASVS-STORAGE: Bộ nhớ
Tổng quan
Tài liệu này đề cập đến một số vấn đề liên quan đến việc đưa tệp vào có các biện pháp giảm thiểu tương tự. Những vấn đề này xoay quanh các lỗ hổng bắt nguồn từ quyền truy cập vào các tệp trong WebView và có phạm vi từ WebSettings
nguy hiểm cho phép truy cập tệp hoặc bật JavaScript, đến một phương thức WebKit tạo yêu cầu chọn tệp. Tài liệu này sẽ hữu ích nếu bạn đang tìm hướng dẫn về cách khắc phục các vấn đề trong WebView phát sinh từ việc sử dụng lược đồ file://
, quyền truy cập không hạn chế vào các tệp cục bộ và tập lệnh chéo trang.
Cụ thể hơn, tài liệu này đề cập đến các chủ đề sau:
WebSettings
là một lớp chứa các phương thức quản lý trạng thái cài đặt cho WebView. Những phương thức này có thể mở WebView cho các cuộc tấn công khác nhau sẽ được trình bày sau. Trong tài liệu này, chúng ta sẽ xem xét các phương thức liên quan đến cách truy cập vào tệp và chế độ cài đặt cho phép thực thi JavaScript:- Bạn có thể sử dụng các phương thức
setAllowFileAccess
,setAllowFileAccessFromFileURLs
vàsetAllowUniversalAccessFromFileURLs
để cấp quyền truy cập vào các tệp cục bộ bằng cách sử dụng URL lược đồ tệp (file://
). Tuy nhiên, các phương thức này có thể bị các tập lệnh độc hại khai thác để truy cập vào các tệp cục bộ tuỳ ý mà ứng dụng có quyền truy cập, chẳng hạn như thư mục/data/
của riêng ứng dụng. Vì lý do này, các phương thức này đã bị gắn cờ là không an toàn và ngừng hoạt động trong API 30 để nhường chỗ cho các phương thức thay thế an toàn hơn, chẳng hạn nhưWebViewAssetLoader
. - Bạn có thể dùng phương thức
setJavascriptEnabled
để cho phép thực thi JavaScript trong WebView. Điều này khiến các ứng dụng dễ bị tấn công XSS dựa trên tệp. Đặc biệt là khi được định cấu hình để cho phép tải các tệp cục bộ hoặc nội dung web không đáng tin cậy có thể chứa mã thực thi, được định cấu hình để cho phép truy cập vào các tệp có thể được tạo hoặc thay đổi bởi các nguồn bên ngoài hoặc cho phép WebView thực thi JavaScript, người dùng và dữ liệu của họ sẽ gặp rủi ro. WebChromeClient.onShowFileChooser
là một phương thức thuộc góiandroid.webkit
, cung cấp các công cụ duyệt web. Bạn có thể dùng phương thức này để cho phép người dùng chọn tệp trong WebView. Tuy nhiên, tính năng này có thể bị lạm dụng vì WebView không thực thi các hạn chế đối với tệp được chọn.
Tác động
Mức độ ảnh hưởng của việc đưa tệp vào có thể phụ thuộc vào WebSettings nào được định cấu hình trong WebView. Quyền truy cập vào tệp quá rộng có thể cho phép kẻ tấn công truy cập vào các tệp cục bộ và đánh cắp dữ liệu nhạy cảm, PII (Thông tin nhận dạng cá nhân) hoặc dữ liệu ứng dụng riêng tư. Việc cho phép thực thi JavaScript có thể tạo điều kiện cho kẻ tấn công chạy JavaScript trong WebView hoặc trên thiết bị của người dùng. Các tệp được chọn bằng phương thức onShowFileChooser
có thể gây rủi ro cho tính bảo mật của người dùng vì phương thức hoặc WebView không có cách nào để đảm bảo rằng nguồn tệp là đáng tin cậy.
Rủi ro: Truy cập vào tệp qua file:// có thể gây rủi ro
Việc bật setAllowFileAccess
, setAllowFileAccessFromFileURLs
và setAllowUniversalAccessFromFileURLs
có thể cho phép các ý định độc hại và yêu cầu WebView có ngữ cảnh file://
truy cập vào các tệp cục bộ tuỳ ý, bao gồm cả cookie WebView và dữ liệu riêng tư của ứng dụng. Ngoài ra, việc sử dụng phương thức onShowFileChooser
có thể cho phép người dùng chọn và tải tệp xuống từ các nguồn không tin cậy.
Tất cả các phương thức này đều có thể dẫn đến việc đánh cắp PII, thông tin đăng nhập hoặc dữ liệu nhạy cảm khác, tuỳ thuộc vào cấu hình ứng dụng.
Giải pháp giảm thiểu
Xác thực URL tệp
Nếu ứng dụng của bạn cần truy cập vào các tệp thông qua URL file://
, thì điều quan trọng là bạn chỉ nên đưa vào danh sách cho phép những URL cụ thể mà bạn biết là hợp lệ, tránh các lỗi thường gặp.
Sử dụng WebViewAssetLoader
Hãy sử dụng WebViewAssetLoader
thay vì các phương thức đã đề cập. Phương thức này sử dụng lược đồ http(s)//:
thay vì lược đồ file://
để truy cập vào các thành phần hệ thống tệp cục bộ và không dễ bị tấn công như mô tả.
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");
Tắt các phương thức WebSettings nguy hiểm
Theo mặc định, các giá trị của phương thức setAllowFileAccess()
, setAllowFileAccessFromFileURLs()
và setAllowUniversalAccessFromFileURLs()
được đặt thành TRUE
ở API cấp 29 trở xuống và FALSE
ở API cấp 30 trở lên.
Nếu cần định cấu hình WebSettings
khác, tốt nhất bạn nên tắt một cách rõ ràng các phương thức này, đặc biệt là đối với những ứng dụng nhắm đến API cấp nhỏ hơn hoặc bằng 29.
Rủi ro: File-Based XSS
Việc đặt phương thức setJavacriptEnabled
thành TRUE
cho phép thực thi JavaScript trong WebView. Ngoài ra, khi kết hợp với quyền truy cập vào tệp (như đã nêu trước đó), bạn có thể thực hiện XSS dựa trên tệp thông qua việc thực thi mã trong các tệp tuỳ ý hoặc các trang web độc hại được mở trong WebView.
Giải pháp giảm thiểu
Ngăn WebView tải tệp cục bộ
Tương tự như rủi ro trước đó, bạn có thể tránh được XSS dựa trên tệp nếu đặt setAllowFileAccess()
, setAllowFileAccessFromFileURLs()
và setAllowUniversalAccessFromFileURLs()
thành FALSE
.
Ngăn WebView thực thi JavaScript
Đặt phương thức setJavascriptEnabled
thành FALSE
để JavaScript không thể thực thi trong WebView.
Đảm bảo WebView không tải nội dung không đáng tin cậy
Đôi khi, bạn cần bật các chế độ cài đặt này trong WebView. Trong trường hợp này, điều quan trọng là bạn phải đảm bảo rằng chỉ nội dung đáng tin cậy mới được tải. Hạn chế việc thực thi JavaScript chỉ đối với những nội dung mà bạn kiểm soát và không cho phép JavaScript tuỳ ý là một cách hay để đảm bảo nội dung đáng tin cậy. Nếu không, việc ngăn tải lưu lượng truy cập ở dạng văn bản thô sẽ đảm bảo rằng các WebView có chế độ cài đặt nguy hiểm ít nhất không thể tải URL HTTP. Bạn có thể thực hiện việc này thông qua tệp kê khai, đặt android:usesCleartextTraffic
thành False
hoặc bằng cách đặt Network Security Config
không cho phép lưu lượng truy cập HTTP.
Tài nguyên
- Trang tham khảo API setAllowUniversalAccessFromFileURLs
- Trang tài liệu tham khảo API setAllowFileAccessFromFileURLs
- Trang tài liệu tham khảo WebViewAssetLoader API
- Tài liệu về CodeQL
- Blog Oversecured
- Trang tham chiếu onShowFileChooser