Origin spoofing
Description
When an RPC request from the embedded browser is received, the wallet needs to identify the origin of the request.
The origin is tracked by an object of type BrowserWebClientID
.
struct BrowserWebClientID : Hashable, CustomStringConvertible {
private let value: String
private init(_ value: String) {
self.value = value
}
init?(from url: URL) {
guard let host = url.host else { return nil }
self.init(host)
}
init(from origin: WKSecurityOrigin) {
self.init(origin.host)
}
// ...
}
Regardless of whether the object is initialized from a URL or from a WKSecurityOrigin, only the host part of the origin is considered, while the protocol and port are ignored.
Impact
This issue causes different origins (for example, https://somedapp.com:443 and http://somedapp.com:8080) to be considered identical.
There are multiple ramifications due to this, but fundamentally this opens up multiple paths that could allow an attacker to spoof the origin of an RPC request.
For example, an attacker on the same network of a victim user could perform a Man in the Middle ("MITM") attack and redirect any page the user visits to a fake plaintext clone of a dApp. Note that the attacker can also do this by altering any HTTP page loaded to inject an iframe with a spoofed origin. The code in the iframe could wait until the page is in background and the user starts using the legitimate dApp and then request a signing operation that would very convincingly be presented as coming from the legitimate dApp.
The RPC message handler determines which webview has originated an RPC request by matching the BrowserWebClientID
constructed from the URL of each open webview with the BrowserWebClientID
constructed from the security origin of the frame (accessing message.frameInfo.securityOrigin
in BrowserWebScriptCoordinator::response
).
This allows a request coming from a background tab or an iframe to be treated as if coming from a different webview and potentially be presented as originating from a legitimate dApp.
Recommendations
Include protocol and port in the elements that are used to represent the origin or an RPC request.
Remediation
This issue was remediated in the following commits:
b779c7954d5b020e2dfe5e2763376ff5bfc721ad
2b5aaec16e69466a112de48e3f27ec45b51dd3ce