Upload
lpilorz
View
2.196
Download
2
Embed Size (px)
DESCRIPTION
OWASP Kraków, January 2014
Citation preview
WebView security on iOSŁukasz Pilorz"
!
OWASP Poland meeting, 29 Jan 2014
Theory
[webView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString:@“http://example.com“] ] ];
!
- loadRequest: !
- loadHTMLString:baseURL: !
- loadData:MIMEType:textEncodingName:baseURL: !
- stringByEvaluatingJavaScriptFromString: !
- goBack !
- goForward !
- stopLoading !
- reload
!id<UIWebViewDelegate> delegate"!NSURLRequest request"!UIDataDetectorTypes dataDetectorTypes"!enum { UIDataDetectorTypePhoneNumber = 1 << 0, UIDataDetectorTypeLink = 1 << 1, UIDataDetectorTypeAddress = 1 << 2, UIDataDetectorTypeCalendarEvent = 1 << 3, UIDataDetectorTypeNone = 0, UIDataDetectorTypeAll = NSUIntegerMax } !… !https://developer.apple.com/library/ios/documentation/uikit/reference/UIWebView_Class/Reference/Reference.html
UIWebViewDelegate
– webView:shouldStartLoadWithRequest:navigationType:
– webViewDidStartLoad:
– webViewDidFinishLoad:
– webView:didFailLoadWithError:
Questions:How to recognize whether navigation happened in top document or a frame?How to block images or JavaScript?Can webViewDidFinishLoad not happen after webViewDidStartLoad?Can webViewDidStartLoad not happen before webViewDidFinishLoad?
Limitations• Lack of Nitro
• HTTP 401 not supported natively
• No option to turn off JavaScript
• [Also applies to Mobile Safari]Content-Disposition: attachment; filename=“download.html”Content-Type: text/plain- guess how will UIWebView behave (see CVE-2011-3426, CVE-2013-5151)
• Blocks JavaScript on scrolling
• Limited support for target attribute and window.open() ~ document.location.assign()
• Does not support RSS
Practice
Advantages• Content update without App Store update
• HTML5 + JavaScript + CSS
• Possibility to re-use code on many platforms (+ Apache Cordova / PhoneGap)
• .html / .key / .numbers / .pages / .xls / .pdf / .ppt / .doc / .rftd.zip / .rtf
• Automatic SSL certificate verification
• Same Origin Policy… non-standard one
Security guidelines• “Ensure that all UIWebView calls do not execute without proper input validation. Apply filters
for dangerous JavaScript characters if possible, using a whitelist over blacklist character policy before rendering. If possible call mobile Safari instead of rending inside of UIWebView which has access to your application.” (OWASP Mobile Top 10)
• “[…] maintain control of all UIWebView content and pages, and prevent the user from accessing arbitrary, untrusted web content.” (OWASP iOS Developer Cheat Sheet)
• “Inspect remote content via the use of the NSData class method dataWithContentsOfURL in an attempt to prohibit the loading of malicious script into a UIWebview. Do not load content remotely and then process the data returned before passing to a UIWebview (if at all avoidable) otherwise you grant local file system access to any malicious script that smuggles itself past your content inspectors.” (MWR Labs blog)
• Sounds dangerous… :-)
UIWebView in iOS applications• Chrome
• Coast
• SkyDrive
• Skype
• WinZip
• and hundreds of others
Secure UIWebView - how to start?Requirements:
• without reducing planned functionality
• without spending weeks on building content filters (and further ones on maintenance and fixes)
• minimal amount of code added
• efficiently
Step 1
Probably NO, if it’s mobile banking:http://blog.ioactive.com/2014/01/personal-banking-apps-leak-info-
through.html
Is UIWebView needed in your application?
YES !
NO
These aren't the droids we're looking for. You can go about your business.
Step 2Do the documents, which you intend to display,
need to be displayed in your application?
YES !
!
!
NO !
Use Safari,Chrome (x-callback-url?)
or another available browser
Step 3Is the presented document loaded directly through HTTP?
YES - loadRequest(…)
!
Use https:// !
Don’t turn off SSL certificate validation
NO - data passed locally
!
!
!
Remember to set baseURL"
!
- loadRequest: !
- loadHTMLString:baseURL: !
- loadData:MIMEType:textEncodingName:baseURL: !
- stringByEvaluatingJavaScriptFromString: !
- goBack !
- goForward !
- stopLoading !
- reload
baseURL vs Same Origin Policy• file:/// can read local files and any URLs - dangerous!
• nil/NULL == applewebdata: same privileges as file: - dangerous!
• by default UIWebView assumes file:// (@“test” == @“file://test”)
• for http(s):// standard Same Origin Policy applies
• for about: and data: also, but with separate origin context
<script>a = document.location.href.split('/');if(a[0]==='file:') { path = ‘file:///'+a[3]+'/'+a[4]+'/'+a[5]+'/'+a[6]+'/'+a[7] +'/Library/Cookies/Cookies.binarycookies'; x = new XMLHttpRequest(); x.open('GET', path, false); x.send(); alert(x.responseText); }</script>
[webView loadHTMLString: [NSString stringWithContentsOfFile:@“/sciezka/do/pliku.html” encoding:NSUTF8StringEncoding error:&error] baseURL:[NSURL URLWithString:@“about:blank”]];
!
Potential problem: images, CSS etc. won’t be loaded from file:///
Example: Chrome for iOS
<!-- CVE-2012-2899 --> !
<script> function test() { pop = window.open('about:blank', '_blank'); pop.document.write( '<script>document.write(document.location)</scr' +'ipt><br><iframe src=“http://example.com/“' +'onload="alert(this.contentDocument.body.innerHTML)"></iframe>' ); } </script> <input type="button" onclick="test()" value=“Click">
Example: Coast by Opera
Step 4Do you have control over the content loaded to UIWebView?
YES - I have control over content
!
Make sure the documents are not vulnerable to XSS
NO - I don’t have control over content
!
Can the user recognize origin? !
Use CSP or HTML sandbox
User interface• clear separation of trusted and untrusted content
• address bar with current URLwebView.request.mainDocumentURL.absoluteStringvs[webView stringByEvaluatingJavaScriptFromString:@"window.location.href"]
• SSL indicator
• warning before first display of untrusted document
• other ideas?
Cross-Site Scripting
• Stored (server-side or in the application)
• Reflected (watch for URL scheme handlers)
• DOM-based (!)
• [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.body.innerText='%@'", input]];
Cross-Site Scripting/JavaScript Injectioninput: ';alert(0)//🌙ꆁ
!
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.body.innerText='%@'", input]];
!
document.body.innerText='';alert(0)//🌙ꆁ'
- (NSString*) escapeForJavaScript:(NSString*)fromString { NSString *toString = @""; for(int i=0;i<fromString.length;i++) { toString = [NSString stringWithFormat:@“%@\\u%04X", toString, [fromString characterAtIndex:i] ]; } return toString; }
escapeForJavaScriptinput: ‘;alert(0)//🌙ꆁ !
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.body.innerText='%@'", [self escapeForJavaScript:input] ]];
document.body.innerText='\u0027\u003B\u0061\u006C\u0065\u0072\u0074\u0028\u0030\u0029\u002F\u002F\uD83C\uDF19\uA181'
innerHTML
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.body.innerHTML='%@'", [self escapeForJavaScript:input] ]]; !
Question: why the above code is not secure?
innerHTMLinput: <img src=x onerror=alert(0)> !
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.body.innerHTML='%@'", [self escapeForJavaScript:input] ]];
document.body.innerHTML='\u003C\u0069\u006D\u0067\u0020\u0073\u0072\u0063\u003D\u0078\u0020\u006F\u006E\u0065\u0072\u0072\u006F\u0072\u003D\u0061\u006C\u0065\u0072\u0074\u0028\u0030\u0029\u003E'
Step 5Additional security
Whitelisting allowed URLs !
http https data
about
Turning off JavaScript !
Content-Security-Policy HTML5 Sandbox
!
What can go wrong?
[webView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString:@“https://unknown.tld/untrusted.php“] ]];
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { NSMutableDictionary *mHeaders = [NSMutableDictionary dictionary]; NSString *CSP = @"default-src 'none'; img-src *;style-src 'unsafe-inline' *;child-src *;frame-src *;sandbox allow-forms allow-top-navigation"; for(id h in response.allHeaderFields) { if(![[h lowercaseString] isEqualToString:@"content-security-policy"] && ![[h lowercaseString] isEqualToString:@"x-webkit-csp"]) { [mHeaders setObject:response.allHeaderFields[h] forKey:h]; } } [mHeaders setObject:CSP forKey:@"Content-Security-Policy"]; [mHeaders setObject:CSP forKey:@"X-Webkit-CSP"]; NSHTTPURLResponse *mResponse = [[NSHTTPURLResponse alloc] initWithURL:response.URL statusCode:response.statusCode HTTPVersion:@"HTTP/1.1" headerFields:mHeaders ]; [self.client URLProtocol:self didReceiveResponse:mResponse cacheStoragePolicy:NSURLCacheStorageNotAllowed ]; }
?
//<UIWebViewDelegate>- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if([request.URL.scheme isEqualToString:@"http" || [request.URL.scheme isEqualToString:@"https"] || [request.URL.scheme isEqualToString:@"about"] || [request.URL.scheme isEqualToString:@“data”]) { return YES; } return NO;}
Question: Will the above code block javascript: URLs? Where?
Step 6What did we forget?
Pentest
Cordova/PhoneGap !
and other Javascript/Objective-C bridges
…
Links(OWASP)
• https://www.owasp.org/index.php/IOS_Application_Security_Testing_Cheat_Sheet
• https://www.owasp.org/index.php/IOS_Developer_Cheat_Sheet
!
(iOS)
• http://www.apple.com/business/accelerator/develop/security.html & https://developer.apple.com/videos/wwdc/2010/
• http://stackoverflow.com/questions/3496505/differences-between-uiwebview-and-mobile-safari
!
(CSP)
• https://www.owasp.org/images/2/2b/Oxdef_csp_poland.pdf & http://niebezpiecznik.pl/OWASP2013-Krakow-CSP.pdf
• http://lists.w3.org/Archives/Public/public-webappsec/2012Mar/0043.html
http://browser-shredders.blogspot.com
Teaser: Breaking iOS browsers (before it will be cool ;-)