Categoría de OWASP: MASVS-PLATFORM: Interacción con la plataforma
Descripción general
Un puente nativo, a veces conocido como puente de JavaScript, es un mecanismo que
facilita la comunicación entre una WebView y el código nativo de Android, que se logra mediante el método addJavascriptInterface. Esto permite la comunicación bidireccional entre el código JavaScript que se ejecuta en la WebView y el código Java de la aplicación para Android. El método addJavascriptInterface expone un objeto Java a todos los marcos de una WebView, y cualquier marco puede acceder al nombre del objeto y llamar a los métodos en él. Sin embargo, no hay ningún mecanismo para que la aplicación verifique el origen del marco de llamada dentro de la WebView, lo que genera problemas de seguridad, ya que la confiabilidad del contenido sigue siendo indeterminada.
También se puede implementar un puente nativo con canales de mensajes HTML usando
Android's WebViewCompat.postWebMessage o
WebMessagePort.postMessage para comunicarse con el JavaScript
Window.postMessage. WebViewCompat.postWebMessage y WebMessagePort.postMessage pueden aceptar mensajes de JavaScript enviados a través de Window.postMessage, que se ejecutarán dentro de la WebView.
Existen varios riesgos asociados con los puentes nativos:
- Puentes basados en JavascriptInterface:
- El método
addJavascriptInterfaceinyecta un objeto Java proporcionado en cada marco de la WebView, incluidos los iframes, lo que significa que es susceptible a ataques de terceros maliciosos que inyectan marcos en un sitio web legítimo. Las aplicaciones orientadas al nivel de API 16 o versiones anteriores corren un riesgo particular de ataque porque este método se puede usar para permitir que JavaScript controle la aplicación host. - Reflejar contenido no confiable proporcionado por el usuario en WebViews habilitadas para puentes nativos permite ataques de secuencias de comandos entre sitios (XSS).
- El método
- Puentes basados en MessageChannel:
- La falta de verificaciones de origen en los extremos del canal de mensajes significa que se aceptarán mensajes de cualquier remitente, incluidos los que contengan código malicioso.
- Es posible exponer Java accidentalmente a JavaScript arbitrario.
Impacto
Los actores maliciosos pueden aprovechar los métodos addJavascriptInterface, postWebMessage y postMessage para acceder, manipular o inyectar código que controlan en una WebView. Esto puede hacer que los usuarios se redireccionen a sitios maliciosos, carguen contenido malicioso o ejecuten código malicioso en sus dispositivos que puedan extraer datos sensibles o lograr la elevación de privilegios.
Riesgo: Riesgos de addJavascriptInterface
WebView implementa funcionalidades básicas de un navegador, como la renderización de páginas, la navegación y la ejecución de JavaScript. WebView se puede usar dentro de una aplicación para mostrar contenido web como parte de un diseño de actividad. La implementación de un puente nativo dentro de una WebView con el método addJavascriptInterface puede crear problemas de seguridad, como secuencias de comandos entre sitios (XSS), o permitir que los atacantes carguen contenido no confiable a través de la inyección de interfaz y manipulen la aplicación host de formas no deseadas, ejecutando código Java con los permisos de la aplicación host.
Mitigaciones
Inhabilitar JavaScript
En situaciones en las que WebView no requiere JavaScript, no llames a
setJavaScriptEnabled dentro de WebSettings (por ejemplo, mientras
se muestra contenido HTML estático). De forma predeterminada, la ejecución de JavaScript está inhabilitada en WebView.
Quita la interfaz de JavaScript cuando cargues contenido no confiable
Asegúrate de que se quiten los objetos de la interfaz de JavaScript llamando a
removeJavascriptInterface antes de que la
WebView cargue contenido que no sea de confianza. Por ejemplo, esto se puede hacer en una llamada a
shouldInterceptRequest.
Kotlin
webView.removeJavascriptInterface("myObject")
Java
webView.removeJavascriptInterface("myObject");
Carga solo contenido web a través de HTTPS
Si necesitas cargar contenido no confiable, asegúrate de que la WebView cargue contenido web a través de
una conexión encriptada (consulta también nuestros lineamientos sobre comunicaciones
de texto simple). Para evitar que la carga de página inicial se realice en conexiones sin encriptar, configura android:usesCleartextTraffic como false en el archivo AndroidManifest o inhabilita el tráfico HTTP en una configuración de seguridad de red. Consulta la usesCleartextTraffic documentación para obtener más
información.
XML
<application
android:usesCleartextTraffic="false">
<!-- Other application elements -->
</application>
Para asegurarte de que las redirecciones y la navegación adicional de la app no se produzcan en el tráfico sin encriptar, verifica el esquema HTTP en loadUrl o
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);
}
}
}
Valida el contenido no confiable
Si se carga algún vínculo externo en una WebView, valida el esquema y el host (dominios de la lista de entidades permitidas). En su lugar, el navegador predeterminado debe abrir cualquier dominio que no esté en la lista de entidades permitidas.
No cargues contenido no confiable
Si es posible, carga solo las URLs y el contenido con permisos estrictos que pertenezcan al desarrollador de la app en WebView.
No expongas datos sensibles
Si tu aplicación accede a datos sensibles con una WebView, considera usar el
clearCache método para borrar los archivos almacenados de forma local antes de usar la
interfaz de JavaScript. También puedes usar encabezados del servidor, como no-store, para indicar que una aplicación no debe almacenar en caché un contenido determinado.
No expongas funcionalidades sensibles
Si tu aplicación requiere permisos sensibles o recopila datos sensibles, asegúrate de que se llame desde el código dentro de la aplicación y que se proporcione una divulgación destacada a los usuarios. Evita usar interfaces de JavaScript para cualquier operación sensible o datos del usuario.
Nivel de API objetivo 21 o superior
Una forma segura de usar el método addJavascriptInterface es segmentar el nivel de API objetivo 21 o uno superior. Para ello, asegúrate de que el método se llame solo cuando se ejecute en el nivel de API 21 o uno superior. Antes de la API 21, JavaScript podía usar la reflexión para acceder a los campos públicos de un objeto inyectado.
Riesgo: Riesgos de MessageChannel
La falta de control de origen en postWebMessage() y postMessage() podría permitir que los atacantes intercepten mensajes o los envíen a controladores nativos.
Mitigaciones
Cuando configures postWebMessage() o postMessage(), permite solo los mensajes de dominios de confianza. Para ello, evita el uso de * como origen de destino y, en su lugar, especifica de forma explícita el dominio de envío esperado.
Recursos
- Prácticas recomendadas de postMessage()
- Documentación de addJavascriptInterface
- Documentación de postMessage()
- Documentación de WebMessagePort.postMessage()
- Documentación de WebViewClient.shouldInterceptRequest
- Documentación sobre consejos de seguridad relacionados con addJavascriptInterface
- Documentación de clearCache
- Documentación de removeJavascript
- Cómo habilitar JavaScript en WebViews