diff --git a/rules/S7409/ask-yourself.adoc b/rules/S7409/ask-yourself.adoc new file mode 100644 index 0000000000..68bb8c4cb0 --- /dev/null +++ b/rules/S7409/ask-yourself.adoc @@ -0,0 +1,8 @@ +== Ask Yourself Whether + +* The content in the WebView is fully trusted and secure. +* Potentially untrusted iframes could be loaded in the WebView. +* The JavaScript interface has to be exposed for the entire lifecycle of the WebView. +* The exposed Java object might be called by untrusted sources. + +There is a risk if you answered yes to any of these questions. diff --git a/rules/S7409/description.adoc b/rules/S7409/description.adoc new file mode 100644 index 0000000000..f349b7bb6f --- /dev/null +++ b/rules/S7409/description.adoc @@ -0,0 +1,5 @@ +Using JavaScript interfaces in WebViews to expose Java objects is unsafe. Doing so allows JavaScript +to invoke Java methods, potentially giving attackers access to data or sensitive app functionality. +WebViews might include untrusted sources such as third-party iframes, making this functionality +particularly risky. As JavaScript interfaces are passed to every frame in the WebView, those iframes +are also able to access the exposed Java object. diff --git a/rules/S7409/java/metadata.json b/rules/S7409/java/metadata.json new file mode 100644 index 0000000000..0af704eda6 --- /dev/null +++ b/rules/S7409/java/metadata.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/rules/S7409/java/rule.adoc b/rules/S7409/java/rule.adoc new file mode 100644 index 0000000000..42a82faf97 --- /dev/null +++ b/rules/S7409/java/rule.adoc @@ -0,0 +1,106 @@ +include::../description.adoc[] + +include::../ask-yourself.adoc[] + +:setJavaScriptEnabledSnippet: webSettings.setJavaScriptEnabled(false) + +include::../recommended.adoc[] + +== Sensitive Code Example + +[source,java] +---- +public class ExampleActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + WebView webView = new WebView(this); + webView.getSettings().setJavaScriptEnabled(true); + webView.addJavascriptInterface(new JavaScriptBridge(), "androidBridge"); // Sensitive + } + + public static class JavaScriptBridge { + @JavascriptInterface + public String accessUserData(String userId) { + return getUserData(userId); + } + } +} +---- + +== Compliant Solution + +The most secure option is to disable JavaScript entirely. S6362 further explains why it should not be enabled +unless absolutely necessary. + +[source,java] +---- +public class ExampleActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + WebView webView = new WebView(this); + webView.getSettings().setJavaScriptEnabled(false); + } +} +---- + +If possible, remove the JavaScript interface after it is no longer needed, or before loading any untrusted content. + +[source,java] +---- +public class ExampleActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + WebView webView = new WebView(this); + webView.getSettings().setJavaScriptEnabled(true); + + webView.addJavascriptInterface(new JavaScriptBridge(), "androidBridge"); + + // Sometime later, before unsafe content is loaded, remove the JavaScript interface + webView.removeJavascriptInterface("androidBridge"); + } +} +---- + +If a JavaScript bridge must be used, consider using ``WebViewCompat.addWebMessageListener`` instead. This allows you to restrict +the origins that can send messages to the JavaScript bridge. + +[source,java] +---- +public class ExampleActivity extends AppCompatActivity { + private static final Set ALLOWED_ORIGINS = Collections.singleton("https://example.com"); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + WebView webView = new WebView(this); + webView.getSettings().setJavaScriptEnabled(true); + + WebViewCompat.addWebMessageListener( + webView, + "androidBridge", + ALLOWED_ORIGINS, // Only allow messages from these origins + new WebMessageListener() { + @Override + public void onPostMessage( + WebView view, + WebMessageCompat message, + Uri sourceOrigin, + boolean isMainFrame, + JavaScriptReplyProxy replyProxy + ) { + // Handle the message + } + } + ); + } +} +---- + +include::../see.adoc[] diff --git a/rules/S7409/kotlin/metadata.json b/rules/S7409/kotlin/metadata.json index 735c52de68..7a73a41bfd 100644 --- a/rules/S7409/kotlin/metadata.json +++ b/rules/S7409/kotlin/metadata.json @@ -1,42 +1,2 @@ { - "title": "Exposing Java objects through JavaScript interfaces is security-sensitive", - "type": "SECURITY_HOTSPOT", - "status": "ready", - "remediation": { - "func": "Constant\/Issue", - "constantCost": "30min" - }, - "tags": [ - "cwe", - "android" - ], - "defaultSeverity": "Major", - "ruleSpecification": "RSPEC-7409", - "sqKey": "S7409", - "scope": "All", - "defaultQualityProfiles": [ - "Sonar way" - ], - "securityStandards": { - "OWASP Mobile": [ - "M1" - ], - "OWASP Mobile Top 10 2024": [ - "M4", - "M8" - ], - "OWASP Top 10 2021": [ - "A5" - ], - "CWE": [ - 79 - ] - }, - "quickfix": "unknown", - "code": { - "impacts": { - "SECURITY": "MEDIUM" - }, - "attribute": "TRUSTWORTHY" - } } \ No newline at end of file diff --git a/rules/S7409/kotlin/rule.adoc b/rules/S7409/kotlin/rule.adoc index a5734e095f..db05893530 100644 --- a/rules/S7409/kotlin/rule.adoc +++ b/rules/S7409/kotlin/rule.adoc @@ -1,43 +1,10 @@ -Using JavaScript interfaces in WebViews to expose Java objects is unsafe. Doing so allows JavaScript -to invoke Java methods, potentially giving attackers access to data or sensitive app functionality. -WebViews might include untrusted sources such as third-party iframes, making this functionality -particularly risky. As JavaScript interfaces are passed to every frame in the WebView, those iframes -are also able to access the exposed Java object. +include::../description.adoc[] -== Ask Yourself Whether +include::../ask-yourself.adoc[] -* The content in the WebView is fully trusted and secure. -* Potentially untrusted iframes could be loaded in the WebView. -* The JavaScript interface has to be exposed for the entire lifecycle of the WebView. -* The exposed Java object might be called by untrusted sources. +:setJavaScriptEnabledSnippet: webSettings.javaScriptEnabled = false -There is a risk if you answered yes to any of these questions. - -== Recommended Secure Coding Practices - -=== Disable JavaScript - -If it is possible to disable JavaScript in the WebView, this is the most secure option. By default, -JavaScript is disabled in a WebView, so ``webSettings.setJavaScriptEnabled(false)`` does not need to -be explicitly called. Of course, sometimes it is necessary to enable JavaScript, in which case the -following recommendations should be considered. - -=== Remove JavaScript interface when loading untrusted content - -JavaScript interfaces can be removed at a later point. It is recommended to remove the JavaScript -interface when it is no longer needed. If it is needed for a longer time, consider removing it before -loading untrusted content. This can be done by calling ``webView.removeJavascriptInterface("interfaceName")``. - -A good place to do this is inside the ``shouldInterceptRequest`` method of a ``WebViewClient``, where you can -check the URL or resource being loaded and remove the interface if the content is untrusted. - -=== Alternative methods to implement native bridges - -If a native bridge has to be added to the WebView, and it is impossible to remove it at a later point, -consider using an alternative method that offers more control over the communication flow. -``WebViewCompat.postWebMessage``/``WebViewCompat.addWebMessageListener`` and ``WebMessagePort.postMessage`` -offer more ways to validate incoming and outgoing messages, such as by being able to restrict the origins -that can send messages to the JavaScript bridge. +include::../recommended.adoc[] == Sensitive Code Example @@ -112,7 +79,9 @@ class ExampleActivity : AppCompatActivity() { webView.settings.javaScriptEnabled = true WebViewCompat.addWebMessageListener( - webView, "androidBridge", ALLOWED_ORIGINS, // Only allow messages from these origins + webView, + "androidBridge", + ALLOWED_ORIGINS, // Only allow messages from these origins object : WebViewCompat.WebMessageListener { override fun onPostMessage( view: WebView, @@ -129,14 +98,4 @@ class ExampleActivity : AppCompatActivity() { } ---- -== See - -* Android Documentation - https://developer.android.com/privacy-and-security/risks/insecure-webview-native-bridges[Insecure WebView native bridges] -* Android Documentation - https://developer.android.com/reference/androidx/webkit/WebViewCompat[WebViewCompat API reference] -* OWASP - https://owasp.org/Top10/A05_2021-Security_Misconfiguration/[Top 10 2021 Category A5 - Security Misconfiguration] -* OWASP - https://owasp.org/www-project-mobile-top-10/2023-risks/m4-insufficient-input-output-validation.html[Mobile Top 10 2024 Category M4 - Insufficient Input/Output Validation] -* OWASP - https://owasp.org/www-project-mobile-top-10/2023-risks/m8-security-misconfiguration.html[Mobile Top 10 2024 Category M8 - Security Misconfiguration] -* CWE - https://cwe.mitre.org/data/definitions/79[CWE-79 - Improper Neutralization of Input During Web Page Generation] - -=== Related rules -* S6362 - Enabling JavaScript support for WebViews is security-sensitive +include::../see.adoc[] \ No newline at end of file diff --git a/rules/S7409/message.adoc b/rules/S7409/message.adoc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/rules/S7409/metadata.json b/rules/S7409/metadata.json index 9e26dfeeb6..02666dcfab 100644 --- a/rules/S7409/metadata.json +++ b/rules/S7409/metadata.json @@ -1 +1,42 @@ -{} \ No newline at end of file +{ + "title": "Exposing Java objects through JavaScript interfaces is security-sensitive", + "type": "SECURITY_HOTSPOT", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "30min" + }, + "tags": [ + "cwe", + "android" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-7409", + "sqKey": "S7409", + "scope": "All", + "defaultQualityProfiles": [ + "Sonar way" + ], + "securityStandards": { + "OWASP Mobile": [ + "M1" + ], + "OWASP Mobile Top 10 2024": [ + "M4", + "M8" + ], + "OWASP Top 10 2021": [ + "A5" + ], + "CWE": [ + 79 + ] + }, + "quickfix": "partial", + "code": { + "impacts": { + "SECURITY": "MEDIUM" + }, + "attribute": "TRUSTWORTHY" + } +} \ No newline at end of file diff --git a/rules/S7409/recommended.adoc b/rules/S7409/recommended.adoc new file mode 100644 index 0000000000..823ef7d51c --- /dev/null +++ b/rules/S7409/recommended.adoc @@ -0,0 +1,25 @@ +== Recommended Secure Coding Practices + +=== Disable JavaScript + +If it is possible to disable JavaScript in the WebView, this is the most secure option. By default, +JavaScript is disabled in a WebView, so ``{setJavaScriptEnabledSnippet}`` does not need to +be explicitly called. Of course, sometimes it is necessary to enable JavaScript, in which case the +following recommendations should be considered. + +=== Remove JavaScript interface when loading untrusted content + +JavaScript interfaces can be removed at a later point. It is recommended to remove the JavaScript +interface when it is no longer needed. If it is needed for a longer time, consider removing it before +loading untrusted content. This can be done by calling ``webView.removeJavascriptInterface("interfaceName")``. + +A good place to do this is inside the ``shouldInterceptRequest`` method of a ``WebViewClient``, where you can +check the URL or resource being loaded and remove the interface if the content is untrusted. + +=== Alternative methods to implement native bridges + +If a native bridge has to be added to the WebView, and it is impossible to remove it at a later point, +consider using an alternative method that offers more control over the communication flow. +``WebViewCompat.postWebMessage``/``WebViewCompat.addWebMessageListener`` and ``WebMessagePort.postMessage`` +offer more ways to validate incoming and outgoing messages, such as by being able to restrict the origins +that can send messages to the JavaScript bridge. diff --git a/rules/S7409/see.adoc b/rules/S7409/see.adoc new file mode 100644 index 0000000000..8b006cacb6 --- /dev/null +++ b/rules/S7409/see.adoc @@ -0,0 +1,11 @@ +== See + +* Android Documentation - https://developer.android.com/privacy-and-security/risks/insecure-webview-native-bridges[Insecure WebView native bridges] +* Android Documentation - https://developer.android.com/reference/androidx/webkit/WebViewCompat[WebViewCompat API reference] +* OWASP - https://owasp.org/Top10/A05_2021-Security_Misconfiguration/[Top 10 2021 Category A5 - Security Misconfiguration] +* OWASP - https://owasp.org/www-project-mobile-top-10/2023-risks/m4-insufficient-input-output-validation.html[Mobile Top 10 2024 Category M4 - Insufficient Input/Output Validation] +* OWASP - https://owasp.org/www-project-mobile-top-10/2023-risks/m8-security-misconfiguration.html[Mobile Top 10 2024 Category M8 - Security Misconfiguration] +* CWE - https://cwe.mitre.org/data/definitions/79[CWE-79 - Improper Neutralization of Input During Web Page Generation] + +=== Related rules +* S6362 - Enabling JavaScript support for WebViews is security-sensitive