Danh mục OWASP: MASVS-PLATFORM: Tương tác với nền tảng
Tổng quan
Cầu gốc (còn gọi là cầu JavaScript) là một cơ chế hỗ trợ giao tiếp giữa WebView và mã Android gốc, được thực hiện 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 chạy trong WebView và mã Java của ứng dụng Android. Phương thức addJavascriptInterface
hiển thị một đối tượng Java cho 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 đó. Tuy nhiên, không có cơ chế nào để áp dụng
xác minh nguồn gốc của khung gọi trong WebView, việc này giúp tăng cường bảo mật
các mối lo ngại do độ tin cậy của nội dung vẫn chưa được xác định.
Bạn cũng có thể triển khai cầu 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 thông 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 gốc:
- Cầu nối dựa trên JavaScriptInterface:
- Phương thức
addJavascriptInterface
chèn một đối tượng Java được cung cấp vào mọi khung của WebView, bao gồm cả iframe, tức là phương thức này dễ bị các bên thứ ba độc hại tấn công bằng cách 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 không đáng tin cậy do người dùng cung cấp trong WebView hỗ trợ cầu 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 nối dựa trên MessageChannel:
- Việc thiếu tính năng 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ừ bất kỳ người gửi nào, bao gồm cả những thông báo chứa mã độc hại.
- Bạn có thể vô tình tiết lộ Java với JavaScript tuỳ ý.
Tác động
Phương thức addJavascriptInterface
, postWebMessage
và postMessage
có thể là
bị các đối tượng độc hại lợi dụng để truy cập, thao túng hoặc chèn mã mà chúng kiểm soát
vào WebView. Việc này có thể khiến 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ọ
có thể trích xuất dữ liệu nhạy cảm hoặc chuyển đặc quyền lên cấp trên.
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. Có thể dùng WebView bên trong một ứng dụng
để hiển thị nội dung web dưới dạng một phần của bố cục hoạt động. Việc triển khai cầu gốc trong WebView bằng phương thức addJavascriptInterface
có thể tạo ra các vấn đề bảo mật như viết 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 tính năng chèn giao diện và thao túng ứng dụng lưu trữ theo cách không mong muốn, thực thi mã Java bằng 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, tính năng thực thi JavaScript 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 xoá các đối tượng khỏi giao diện JavaScript 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 tới
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 kết nối được mã hoá (xem thêm nguyên tắc của chúng tôi về Giao tiếp văn bản thô). Ngăn tải trang ban đầu thực hiện trên
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 một bảo mật mạng
config. Xem tài liệu về usesCleartextTraffic
để biết thêm thông tin
của bạn.
XML
<application
android:usesCleartextTraffic="false">
<!-- Other application elements -->
</application>
Để đảm bảo rằng các lệnh chuyển hướng và duyệt xem thêm ứng dụng không xảy ra trên các kênh chưa mã hoá
lưu lượng truy cập, kiểm tra giao thứ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ó bất kỳ đường liên kết ngoài nào được tải trong WebView, hãy xác thực cả giao thức và máy chủ lưu trữ (các miền trong danh sách cho phép). Bất kỳ miền nào 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 các URL và nội dung mà ứng dụng sở hữu trong phạm vi nghiêm ngặt vào WebView.
Không tiết 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 thuộc tính
clearCache
để xoá mọi tệp được lưu trữ trên máy, 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.
Không hiển thị các chức năng nhạy cảm
Nếu ứng dụng của bạn yêu cầu quyền nhạy cảm hoặc thu thập dữ liệu nhạy cảm, đảm bảo rằng mã được gọi từ mã trong ứng dụng và được cung cấp cho người dùng. Tránh sử dụng giao diện JavaScript cho bất kỳ hoạt động nhạy cảm hoặc dữ liệu người dùng.
API mục tiêu cấp 21 trở lên
Một cách an toàn để sử dụng phương thức addJavascriptInterface
là nhắm đến API cấp 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 API cấp 21 trở lên. Trước API 21, JavaScript có thể dùng tính năng phản chiếu để truy cập vào dữ liệu công khai
của một đối tượng được chèn.
Rủi ro: Rủi ro của MessageChannel
Việc thiếu tính năng kiểm soát nguồn gốc 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 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 tin nhắn từ
các miền đáng tin cậy bằng cách tránh dùng * làm nguồn gốc đích mà thay vào đó
chỉ định rõ 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 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 tư vấn bảo mật liên quan đến addJavaScriptInterface
- Tài liệu về clearCache
- Tài liệu removeJavaScript
- bật JavaScript trong WebView