3
3
*/
4
4
5
5
import java
6
- private import semmle.code.java.frameworks.android.WebView
7
6
private import semmle.code.java.dataflow.DataFlow
8
- private import semmle.code.java.dataflow.ExternalFlow
7
+ private import semmle.code.java.frameworks.android.WebView
9
8
10
9
/**
11
10
* A sink that represents a method that fetches a web resource in Android.
@@ -26,11 +25,9 @@ abstract class UrlResourceSink extends DataFlow::Node {
26
25
*/
27
26
private class CrossOriginUrlResourceSink extends JavaScriptEnabledUrlResourceSink {
28
27
CrossOriginUrlResourceSink ( ) {
29
- exists ( Variable settings , MethodAccess ma |
30
- webViewLoadUrl ( this .asExpr ( ) , settings ) and
31
- ma .getMethod ( ) instanceof CrossOriginAccessMethod and
32
- ma .getArgument ( 0 ) .( BooleanLiteral ) .getBooleanValue ( ) = true and
33
- ma .getQualifier ( ) = settings .getAnAccess ( )
28
+ exists ( WebViewRef webview |
29
+ webViewLoadUrl ( this .asExpr ( ) , webview ) and
30
+ isAllowFileAccessEnabled ( webview )
34
31
)
35
32
}
36
33
@@ -44,57 +41,96 @@ private class CrossOriginUrlResourceSink extends JavaScriptEnabledUrlResourceSin
44
41
*/
45
42
private class JavaScriptEnabledUrlResourceSink extends UrlResourceSink {
46
43
JavaScriptEnabledUrlResourceSink ( ) {
47
- exists ( Variable settings |
48
- webViewLoadUrl ( this .asExpr ( ) , settings ) and
49
- isJSEnabled ( settings )
44
+ exists ( WebViewRef webview |
45
+ webViewLoadUrl ( this .asExpr ( ) , webview ) and
46
+ isJSEnabled ( webview )
50
47
)
51
48
}
52
49
53
50
override string getSinkType ( ) { result = "user input vulnerable to XSS attacks" }
54
51
}
55
52
53
+ private class WebViewRef extends Element {
54
+ WebViewRef ( ) {
55
+ this .( RefType ) .getASourceSupertype * ( ) instanceof TypeWebView or
56
+ this .( Variable ) .getType ( ) .( RefType ) .getASourceSupertype * ( ) instanceof TypeWebView
57
+ }
58
+
59
+ /** Gets an access to this WebView as a data flow node. */
60
+ DataFlow:: Node getAnAccess ( ) {
61
+ exists ( DataFlow:: InstanceAccessNode t | t .getType ( ) = this and result = t |
62
+ t .isOwnInstanceAccess ( ) or t .getInstanceAccess ( ) .isEnclosingInstanceAccess ( this )
63
+ )
64
+ or
65
+ result = DataFlow:: exprNode ( this .( Variable ) .getAnAccess ( ) )
66
+ }
67
+ }
68
+
56
69
/**
57
- * Holds if a `WebViewLoadUrlMethod` method is called with the given `urlArg` on a
58
- * WebView with settings stored in `settings` .
70
+ * Holds if a `WebViewLoadUrlMethod` is called on an access of `webview`
71
+ * with `urlArg` as its first argument .
59
72
*/
60
- private predicate webViewLoadUrl ( Expr urlArg , Variable settings ) {
61
- exists ( MethodAccess loadUrl , Variable webview , MethodAccess getSettings |
73
+ private predicate webViewLoadUrl ( Argument urlArg , WebViewRef webview ) {
74
+ exists ( MethodAccess loadUrl |
62
75
loadUrl .getArgument ( 0 ) = urlArg and
63
- loadUrl .getMethod ( ) instanceof WebViewLoadUrlMethod and
64
- loadUrl .getQualifier ( ) = webview .getAnAccess ( ) and
65
- getSettings .getMethod ( ) instanceof WebViewGetSettingsMethod and
66
- webview .getAnAccess ( ) = getSettings .getQualifier ( ) and
67
- settings .getAnAssignedValue ( ) = getSettings
76
+ loadUrl .getMethod ( ) instanceof WebViewLoadUrlMethod
77
+ |
78
+ webview .getAnAccess ( ) = DataFlow:: getInstanceArgument ( loadUrl )
79
+ or
80
+ // `webview` is received as a parameter of an event method in a custom `WebViewClient`,
81
+ // so we need to find `WebViews` that use that specific `WebViewClient`.
82
+ exists ( WebViewClientEventMethod eventMethod , MethodAccess setWebClient |
83
+ setWebClient .getMethod ( ) instanceof WebViewSetWebViewClientMethod and
84
+ setWebClient .getArgument ( 0 ) .getType ( ) = eventMethod .getDeclaringType ( ) and
85
+ loadUrl .getQualifier ( ) = eventMethod .getWebViewParameter ( ) .getAnAccess ( )
86
+ |
87
+ webview .getAnAccess ( ) = DataFlow:: getInstanceArgument ( setWebClient )
88
+ )
68
89
)
69
90
}
70
91
71
92
/**
72
- * A method allowing any-local-file and cross-origin access in the WebSettings class.
93
+ * Holds if `webview`'s option `setJavascriptEnabled`
94
+ * has been set to `true` via a `WebSettings` object obtained from it.
73
95
*/
74
- private class CrossOriginAccessMethod extends Method {
75
- CrossOriginAccessMethod ( ) {
76
- this .getDeclaringType ( ) instanceof TypeWebSettings and
77
- this .hasName ( [ "setAllowUniversalAccessFromFileURLs" , "setAllowFileAccessFromFileURLs" ] )
78
- }
96
+ private predicate isJSEnabled ( WebViewRef webview ) {
97
+ exists ( MethodAccess allowJs , MethodAccess settings |
98
+ allowJs .getMethod ( ) instanceof AllowJavaScriptMethod and
99
+ allowJs .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getBooleanValue ( ) = true and
100
+ settings .getMethod ( ) instanceof WebViewGetSettingsMethod and
101
+ DataFlow:: localExprFlow ( settings , allowJs .getQualifier ( ) ) and
102
+ DataFlow:: localFlow ( webview .getAnAccess ( ) , DataFlow:: getInstanceArgument ( settings ) )
103
+ )
79
104
}
80
105
81
106
/**
82
- * The `setJavaScriptEnabled` method for the webview.
107
+ * Holds if `webview`'s options `setAllowUniversalAccessFromFileURLs` or
108
+ * `setAllowFileAccessFromFileURLs` have been set to `true` via a `WebSettings` object
109
+ * obtained from it.
83
110
*/
84
- private class AllowJavaScriptMethod extends Method {
85
- AllowJavaScriptMethod ( ) {
86
- this .getDeclaringType ( ) instanceof TypeWebSettings and
87
- this .hasName ( "setJavaScriptEnabled" )
88
- }
111
+ private predicate isAllowFileAccessEnabled ( WebViewRef webview ) {
112
+ exists ( MethodAccess allowFileAccess , MethodAccess settings |
113
+ allowFileAccess .getMethod ( ) instanceof CrossOriginAccessMethod and
114
+ allowFileAccess .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getBooleanValue ( ) = true and
115
+ settings .getMethod ( ) instanceof WebViewGetSettingsMethod and
116
+ DataFlow:: localExprFlow ( settings , allowFileAccess .getQualifier ( ) ) and
117
+ DataFlow:: localFlow ( webview .getAnAccess ( ) , DataFlow:: getInstanceArgument ( settings ) )
118
+ )
89
119
}
90
120
91
- /**
92
- * Holds if a call to `v.setJavaScriptEnabled(true)` exists.
93
- */
94
- private predicate isJSEnabled ( Variable v ) {
95
- exists ( MethodAccess jsa |
96
- v .getAnAccess ( ) = jsa .getQualifier ( ) and
97
- jsa .getMethod ( ) instanceof AllowJavaScriptMethod and
98
- jsa .getArgument ( 0 ) .( BooleanLiteral ) .getBooleanValue ( ) = true
99
- )
121
+ /** A method of the class `WebViewClient` that handles an event. */
122
+ private class WebViewClientEventMethod extends Method {
123
+ WebViewClientEventMethod ( ) {
124
+ this .getDeclaringType ( ) .getASupertype * ( ) instanceof TypeWebViewClient and
125
+ this .hasName ( [
126
+ "shouldOverrideUrlLoading" , "shouldInterceptRequest" , "onPageStarted" , "onPageFinished" ,
127
+ "onLoadResource" , "onPageCommitVisible" , "onTooManyRedirects"
128
+ ] )
129
+ }
130
+
131
+ /** Gets a `WebView` parameter of this method. */
132
+ Parameter getWebViewParameter ( ) {
133
+ result = this .getAParameter ( ) and
134
+ result .getType ( ) instanceof TypeWebView
135
+ }
100
136
}
0 commit comments