Swift: Check for tainted baseURL.

This commit is contained in:
Geoffrey White
2022-08-03 09:17:34 +01:00
parent 53ea65b045
commit 651b73e21e
3 changed files with 48 additions and 5 deletions

View File

@@ -96,7 +96,8 @@ class UnsafeWebViewFetchConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node node) {
node instanceof Sink
node instanceof Sink or
node.asExpr() = any(Sink s).getBaseURL()
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
@@ -111,6 +112,16 @@ class UnsafeWebViewFetchConfig extends TaintTracking::Configuration {
// allow flow through string concatenation.
// TODO: this should probably be part of TaintTracking.
node2.asExpr().(AddExpr).getAnOperand() = node1.asExpr()
or
// allow flow through `URL.init`.
exists(CallExpr call, ClassDecl c, AbstractFunctionDecl f |
c.getName() = "URL" and
c.getAMember() = f and
f.getName() = ["init(string:)", "init(string:relativeTo:)"] and
call.getFunction().(ApplyExpr).getStaticTarget() = f and
node1.asExpr() = call.getArgument(_).getExpr() and
node2.asExpr() = call
)
}
}
@@ -124,5 +135,9 @@ where
// base URL is nil
sink.getBaseURL() instanceof NilLiteralExpr and
message = "Tainted data is used in a WebView fetch without restricting the base URL."
or
// base URL is tainted
config.hasFlow(_, any(DataFlow::Node n | n.asExpr() = sink.getBaseURL())) and
message = "Tainted data is used in a WebView fetch with a tainted base URL."
)
select sinkNode, sourceNode, sinkNode, message

View File

@@ -8,14 +8,26 @@ edges
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:124:25:124:51 | ... call to +(_:_:) ... |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:135:25:135:25 | remoteString |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:137:25:137:25 | remoteString |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:138:47:138:56 | ...! |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:139:48:139:57 | ...! |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:140:47:140:57 | ...! |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:141:48:141:58 | ...! |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:153:85:153:94 | ...! |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:154:86:154:95 | ...! |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:171:25:171:51 | ... call to +(_:_:) ... |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:182:25:182:25 | remoteString |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:184:25:184:25 | remoteString |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:185:47:185:56 | ...! |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:186:48:186:57 | ...! |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:187:47:187:57 | ...! |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:188:48:188:58 | ...! |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:200:90:200:99 | ...! |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:201:91:201:100 | ...! |
nodes
| UnsafeWebViewFetch.swift:94:10:94:37 | try ... : | semmle.label | try ... : |
| UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | semmle.label | call to ... : |
@@ -25,21 +37,37 @@ nodes
| UnsafeWebViewFetch.swift:124:25:124:51 | ... call to +(_:_:) ... | semmle.label | ... call to +(_:_:) ... |
| UnsafeWebViewFetch.swift:135:25:135:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:137:25:137:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:138:47:138:56 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:139:48:139:57 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:140:47:140:57 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:141:48:141:58 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:153:85:153:94 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:154:86:154:95 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | semmle.label | call to getRemoteData() : |
| UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | semmle.label | call to getRemoteData() |
| UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:171:25:171:51 | ... call to +(_:_:) ... | semmle.label | ... call to +(_:_:) ... |
| UnsafeWebViewFetch.swift:182:25:182:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:184:25:184:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:185:47:185:56 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:186:48:186:57 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:187:47:187:57 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:188:48:188:58 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:200:90:200:99 | ...! | semmle.label | ...! |
| UnsafeWebViewFetch.swift:201:91:201:100 | ...! | semmle.label | ...! |
subpaths
#select
| UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:124:25:124:51 | ... call to +(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:124:25:124:51 | ... call to +(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. |
| UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. |
| UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:171:25:171:51 | ... call to +(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:171:25:171:51 | ... call to +(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. |
| UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. |

View File

@@ -136,9 +136,9 @@ func testUIWebView() {
webview.loadHTMLString(localString, baseURL: localURL!) // GOOD: a presumed safe baseURL is specified
webview.loadHTMLString(remoteString, baseURL: localURL!) // GOOD: a presumed safe baseURL is specified
webview.loadHTMLString(localString, baseURL: remoteURL!) // GOOD: the HTML data is local
webview.loadHTMLString(remoteString, baseURL: remoteURL!) // BAD [NOT DETECTED]
webview.loadHTMLString(remoteString, baseURL: remoteURL!) // BAD
webview.loadHTMLString(localString, baseURL: remoteURL2!) // GOOD: the HTML data is local
webview.loadHTMLString(remoteString, baseURL: remoteURL2!) // BAD [NOT DETECTED]
webview.loadHTMLString(remoteString, baseURL: remoteURL2!) // BAD
let localRequest = URLRequest(url: localURL!)
let remoteRequest = URLRequest(url: remoteURL!)
@@ -183,9 +183,9 @@ func testWKWebView() {
webview.loadHTMLString(localString, baseURL: localURL!) // GOOD: a presumed safe baseURL is specified
webview.loadHTMLString(remoteString, baseURL: localURL!) // GOOD: a presumed safe baseURL is specified
webview.loadHTMLString(localString, baseURL: remoteURL!) // GOOD: the HTML data is local
webview.loadHTMLString(remoteString, baseURL: remoteURL!) // BAD [NOT DETECTED]
webview.loadHTMLString(remoteString, baseURL: remoteURL!) // BAD
webview.loadHTMLString(localString, baseURL: remoteURL2!) // GOOD: the HTML data is local
webview.loadHTMLString(remoteString, baseURL: remoteURL2!) // BAD [NOT DETECTED]
webview.loadHTMLString(remoteString, baseURL: remoteURL2!) // BAD
let localRequest = URLRequest(url: localURL!)
let remoteRequest = URLRequest(url: remoteURL!)