Thursday, June 12, 2014
Exploring and Exploiting iOS Web Browsers - part 1
UIWebView is the component used to load web content into iOS applications - basically it's Mobile Safari with the UI stripped off, leaving just the viewport part. Some of the differences:
1. UIWebView can only view a single document at a time (+ frames)
For example, links with target="_blank" will work as target="_top", and window.open() will work more or less the same as location.assign().
2. There is also no UI for error events
The user will not be asked for accepting invalid SSL certificate, will not be informed the connection to the given host failed, etc. However, JavaScript-initiated alerts and prompts are shown (and are not controllable through available API).
3. There is an API to control UIWebView content and behaviour
(By the way, you may want to take a look at this presentation from OWASP Poland meeting.)
Browsers using UIWebViews have to add the user interface - this means at least address bar and error handling. Usually to do this programmers implement UIWebViewDelegate methods:
webViewDidStartLoad:
webViewDidFinishLoad:
webView:didFailLoadWithError:
The last one causes problems usually. The most common issue is lack of address bar update within this method. This may allow an attacker to spoof the address bar by forcing some kind of an error. Apart from events like invalid SSL certificate, NXDOMAIN DNS response or simply response timeout, this method is also called when document.write() function interrupts page load or replaces loaded page.
Lack of address bar update on webView:didFailLoadWithError: was the reason for about a half of the address bar spoofing vulnerabilities we reported to browser authors. Most of the second half was due to updating address bar too early - as soon as the navigation was initiated, before the document actually started loading into UIWebView ("loading loop" from the HITB presentation is an example). By combining both techniques, an attacker can be almost sure the address bar will point to whatever she/he wishes.
See you in the next part soon.
Sunday, February 09, 2014
JavaScript Off for iOS
While testing UIWebView on iOS I found out there is no option to turn off JavaScript for web content. Initially I tried to use HTML5 "sandbox" attribute do achieve this, but in practice Content Security Policy is a much more flexible solution. Injecting CSP headers into NSHTTPURLResponse seems to work even for file: and data: URL schemes.
A sample application testing above solution is available on GitHub, and a similar solution has recently made its way into Onion Browser as an experimental feature. I am looking forward to see how it's going to work in practice.
On a side note, Quick Look is another solution if you need to load a single HTML document with JavaScript turned off.
iOS UIWebView baseURL
UIWebView is one of the most popular components in Cocoa Touch library. It can be used to easily embed web content into iOS applications and - of course - to equally easily introduce Cross-Site Scripting vulnerabilities.
When loading content into webView on iOS, a programmer can choose one of three methods:
- – loadData:MIMEType:textEncodingName:baseURL:
- – loadHTMLString:baseURL:
- – loadRequest:
Did you notice baseURL in the first two? This inconspicuous parameter is quite important when dealing with XSS.
Same Origin Policy works a bit different in iOS than we're used to in desktop browsers, namely file: and applewebdata: URLs have complete cross-origin access to any web resources, in addition to local file access. This means if you save untrusted HTML document locally and then call loadRequest method to load it from its file:/// path into UIWebView, you're simply creating a universal Cross-Site Scripting vulnerability. This document can now read all cookies stored by the application, call JavaScript across domains (including your corporate intranet), and do all that stuff Same Origin Policy usually prevents.
Alternatively to loading untrusted local file with loadRequest, you may first read its content and then use one of the two remaining methods: loadData or loadHTMLString. Unfortunately, by default UIWebView content is loaded with file/applewebdata privileges. This is where the baseURL comes in handy. Simply set the baseURL to "about:blank" URL and Same Origin Policy will prevent cross-origin access (as it probably should do by default, Apple?).
Of course this won't be enough if a webView contains sensitive data and untrusted content at the same time, or if you bridge JavaScript with Objective-C through special URLs catched in webView:shouldStartLoadWithRequest:request. In such cases you should remove all XSS vulnerabilities from your application, one by one.
Sunday, February 02, 2014
WebView security in iOS - presentation from OWASP Poland meeting
Original (Polish) version: http://www.slideshare.net/lpilorz/webview-security-on-ios-pl