Danh mục OWASP: MASVS-PLATFORM: Tương tác với nền tảng
Tổng quan
Cầu nối gốc (đôi khi còn gọi là cầu nối JavaScript) là một cơ chế tạo điều kiện giao tiếp giữa WebView và mã Android gốc, đạt được bằng cách sử dụng phương thức addJavascriptInterface. Điều này cho phép giao tiếp hai chiều giữa mã JavaScript đang chạy trong WebView và mã Java của ứng dụng Android. Phương thức addJavascriptInterface cho phép một đối tượng Java truy cập vào tất cả các khung của WebView và mọi khung đều có thể truy cập vào tên đối tượng và gọi các phương thức trên đối tượng đó. Tuy nhiên, không có cơ chế nào để ứng dụng xác minh nguồn gốc của khung gọi trong WebView. Điều này làm dấy lên lo ngại về bảo mật vì độ tin cậy của nội dung vẫn chưa xác định được.
Bạn cũng có thể triển khai cầu nối gốc bằng các kênh thông báo HTML bằng cách sử dụng WebViewCompat.postWebMessage hoặc WebMessagePort.postMessage của Android để giao tiếp với Window.postMessage JavaScript. WebViewCompat.postWebMessage và WebMessagePort.postMessage có thể chấp nhận các thông báo JavaScript được gửi qua Window.postMessage. Các thông báo này sẽ được thực thi trong WebView.
Có nhiều rủi ro liên quan đến cầu nối gốc:
- Cầu dựa trên JavascriptInterface:
- Phương thức
addJavascriptInterfacechèn một đối tượng Java được cung cấp vào mọi khung của WebView, kể cả iframe. Điều này có nghĩa là phương thức này dễ bị tấn công bởi các bên thứ ba độc hại chèn khung vào một trang web hợp pháp. Các ứng dụng nhắm đến API cấp 16 trở xuống đặc biệt có nguy cơ bị tấn công vì phương thức này có thể được dùng để cho phép JavaScript kiểm soát ứng dụng lưu trữ. - Việc phản ánh nội dung do người dùng cung cấp không đáng tin cậy trong WebView có hỗ trợ cầu nối gốc cho phép các cuộc tấn công thông qua tập lệnh trên nhiều trang web (XSS).
- Phương thức
- Cầu dựa trên MessageChannel:
- Việc thiếu các bước kiểm tra nguồn gốc trên các điểm cuối của kênh thông báo có nghĩa là thông báo sẽ được chấp nhận từ mọi người gửi, kể cả những người gửi có chứa mã độc.
- Có thể vô tình để lộ Java cho JavaScript tuỳ ý.
Tác động
Các phương thức addJavascriptInterface, postWebMessage và postMessage có thể bị các đối tượng xấu lợi dụng để truy cập, thao tác hoặc chèn mã mà họ kiểm soát vào WebView. Điều này có thể dẫn đến việc người dùng bị chuyển hướng đến các trang web độc hại, tải nội dung độc hại hoặc có mã độc chạy trên thiết bị của họ. Mã độc này có thể trích xuất dữ liệu nhạy cảm hoặc đạt được đặc quyền leo thang.
Rủi ro: Rủi ro addJavascriptInterface
WebView triển khai các chức năng cơ bản của trình duyệt, chẳng hạn như kết xuất trang, điều hướng và thực thi JavaScript. Bạn có thể sử dụng WebView trong một ứng dụng để hiển thị nội dung trên web trong bố cục hoạt động. Việc triển khai một cầu nối gốc trong WebView bằng phương thức addJavascriptInterface có thể gây ra các vấn đề về bảo mật như tập lệnh trên nhiều trang web (XSS) hoặc cho phép kẻ tấn công tải nội dung không đáng tin cậy thông qua việc chèn giao diện và thao tác ứng dụng lưu trữ theo những cách không mong muốn, thực thi mã Java bằng các quyền của ứng dụng lưu trữ.
Giải pháp giảm thiểu
Tắt JavaScript
Trong trường hợp WebView không yêu cầu JavaScript, đừng gọi setJavaScriptEnabled trong WebSettings (ví dụ: trong khi hiển thị nội dung HTML tĩnh). Theo mặc định, quy trình thực thi JavaScript sẽ bị tắt trong WebView.
Xoá giao diện JavaScript khi tải nội dung không đáng tin cậy
Đảm bảo các đối tượng trong giao diện JavaScript được xoá bằng cách gọi removeJavascriptInterface trước khi WebView tải nội dung không đáng tin cậy. Ví dụ: bạn có thể thực hiện việc này trong lệnh gọi đến shouldInterceptRequest.
Kotlin
webView.removeJavascriptInterface("myObject")
Java
webView.removeJavascriptInterface("myObject");
Chỉ tải nội dung web qua HTTPS
Nếu bạn cần tải nội dung không đáng tin cậy, hãy đảm bảo WebView tải nội dung web qua một kết nối được mã hoá (xem thêm nguyên tắc của chúng tôi về Thông tin liên lạc bằng văn bản thuần tuý). Ngăn quá trình tải trang ban đầu được thực hiện trên các kết nối chưa mã hoá bằng cách đặt android:usesCleartextTraffic thành false trong tệp AndroidManifest hoặc không cho phép lưu lượng truy cập HTTP trong cấu hình bảo mật mạng. Hãy xem tài liệu usesCleartextTraffic để biết thêm thông tin.
XML
<application
android:usesCleartextTraffic="false">
<!-- Other application elements -->
</application>
Để đảm bảo rằng lệnh chuyển hướng và hoạt động duyệt xem ứng dụng khác không xảy ra trên lưu lượng truy cập chưa mã hoá, hãy kiểm tra lược đồ HTTP trong loadUrl hoặc shouldInterceptRequest:
Kotlin
fun loadSecureUrl(webView: WebView?, url: String?) {
webView?.let { wv -> // Ensure valid WebView and URL
url?.let {
try {
val uri = URI(url)
if (uri.scheme.equals("https", ignoreCase = true)) { // Enforce HTTPS scheme for security
wv.loadUrl(url)
} else {
// Log an error or handle the case where the URL is not secure
System.err.println("Attempted to load a non-HTTPS URL: $url")
}
} catch (e: Exception) {
// Handle exception for improper URL format
System.err.println("Invalid URL syntax: $url")
}
}
}
}
Java
public void loadSecureUrl(WebView webView, String url) {
if (webView != null && url != null) { // Ensure valid WebView and URL
try {
URI uri = new URI(url);
String scheme = uri.getScheme();
if ("https".equalsIgnoreCase(scheme)) { // Enforce HTTPS scheme for security
webView.loadUrl(url);
} else {
// Log an error or handle the case where the URL is not secure
System.err.println("Attempted to load a non-HTTPS URL: " + url);
}
} catch (URISyntaxException e) {
// Handle exception for improper URL format
System.err.println("Invalid URL syntax: " + url);
}
}
}
Xác thực nội dung không đáng tin cậy
Nếu có đường liên kết bên ngoài nào được tải trong WebView, hãy xác thực cả lược đồ và máy chủ lưu trữ (miền trong danh sách cho phép). Mọi miền không có trong danh sách cho phép đều phải được mở bằng trình duyệt mặc định.
Không tải nội dung không đáng tin cậy
Nếu có thể, chỉ tải những nội dung và URL mà nhà phát triển ứng dụng đã giới hạn phạm vi một cách nghiêm ngặt vào WebView.
Đừng để lộ dữ liệu nhạy cảm
Nếu ứng dụng của bạn truy cập vào dữ liệu nhạy cảm bằng WebView, hãy cân nhắc sử dụng phương thức clearCache để xoá mọi tệp được lưu trữ trên thiết bị trước khi sử dụng giao diện JavaScript. Bạn cũng có thể sử dụng các tiêu đề phía máy chủ, chẳng hạn như no-store, để cho biết rằng ứng dụng không nên lưu nội dung cụ thể vào bộ nhớ đệm.
Đừng để lộ các chức năng nhạy cảm
Nếu ứng dụng của bạn yêu cầu các quyền truy cập thông tin nhạy cảm hoặc thu thập dữ liệu nhạy cảm, hãy đảm bảo rằng ứng dụng được gọi từ mã trong ứng dụng và người dùng được cung cấp thông tin công bố nổi bật. Tránh sử dụng giao diện JavaScript cho mọi thao tác nhạy cảm hoặc dữ liệu người dùng.
Nhắm đến cấp độ API mục tiêu 21 trở lên
Một cách bảo mật để sử dụng phương thức addJavascriptInterface là nhắm đến cấp độ API mục tiêu 21 trở lên bằng cách đảm bảo phương thức này chỉ được gọi khi chạy trên cấp độ API 21 trở lên. Trước API 21, JavaScript có thể sử dụng tính năng phản chiếu để truy cập vào các trường công khai của một đối tượng được chèn.
Rủi ro: Rủi ro MessageChannel
Việc thiếu quyền kiểm soát nguồn trong postWebMessage() và postMessage() có thể cho phép kẻ tấn công chặn tin nhắn hoặc gửi tin nhắn đến các trình xử lý gốc.
Giải pháp giảm thiểu
Khi thiết lập postWebMessage() hoặc postMessage(), chỉ cho phép các thông báo từ các miền đáng tin cậy bằng cách tránh sử dụng * làm nguồn gốc mục tiêu và thay vào đó, hãy chỉ định rõ ràng miền gửi dự kiến.
Tài nguyên
- Các phương pháp hay nhất về postMessage()
- Tài liệu về addJavascriptInterface
- Tài liệu về postMessage()
- Tài liệu về WebMessagePort.postMessage()
- Tài liệu về WebViewClient.shouldInterceptRequest
- Tài liệu về lời khuyên bảo mật liên quan đến addJavascriptInterface
- Tài liệu về clearCache
- Tài liệu về removeJavascript
- bật JavaScript trong WebView