内容简介:Imagine you’re a web developer who’s got a little bit of Android experience. You’ve built a progressive web app—it’s beautiful, functional, responsive. Everything the user sees was meticulously placed and crafted with purpose. You’re proud of what you’ve d
Imagine you’re a web developer who’s got a little bit of Android experience. You’ve built a progressive web app—it’s beautiful, functional, responsive. Everything the user sees was meticulously placed and crafted with purpose. You’re proud of what you’ve done. Why wouldn’t you be? Now. How do you take this web-centric experience and apply an Android veneer? Like most devs, you’ll probably find yourself reaching for a WebView . It presents a web page as the app’s interface, along with a basket of other features. Incredibly convenient!
Lets say your site has an interface that’s constantly being updated. Would you want to deploy a new app build every time? Of course not. You pull that shit in dynamically with a WebView. This way, your customers get the benefit of a native platform, with the update speed of a live website.
WebViews also offer complete customization over the UI. To get the same level of control, the alternative would be to either use the built-in components that Android provides, combine them, or create your own from scratch . Basically, with WebViews:
- No need to redeploy for every change.
- Quick testing with common tools that web developers are already used to.
- App can utilize app functionality which may not have proper API’s (yet).
- Customizability with relatively lower effort.
As you might expect, this doesn’t come for free. When implemented incorrectly, there could be extensive security implications. WebView ushers in convenience, but it also significantly increases attack surface. Such is the case for WebView on Android. Security researchers have wasted no time exploring exploring attack vectors believed to be mitigated on browsers, but are still viable within WebViews.
In this article, we explore a paper by GuangLiang Yang, Jeff Huang, and Guofei Gu presented at USENIX 2019 They explored the well-understood topic of <iframe>
security within a WebView context. The paper focuses on what they call Differential Context Vulnerabilities (DCV) . A web page running within a WebView, as opposed to running in a browser, may introduce vulnerabilities given the differences of the context it runs in. They discovered that although most vulnerabilities have had safeguards introduced in full browsers, those same mitigations are either ineffective or impossible to apply within the context of WebViews.
We’ll take a look at some of the attacks they cover.
Design Flaws
WebViews are an interesting target for two primary reasons: their compact design, and their wealth of settings ripe for misconfiguration.
Compact Design
All attacks take advantage of the fact that unlike traditional browsers, WebViews do not provide enough context for the end user whenever navigation occurs. Browsers have address, navigation and status bars, in addition to tab controls. It’s easy for a user to tell what page they’re on and when they’re navigating away from it. This is not the case for WebViews, which simply renders the top most page within its rendering queue.
Insecure settings
The authors do not claim that all WebViews are insecure. Rather, they focus on an insecure combination of settings that an app developer may utilize:
Setting/Method | Impact |
---|---|
WebSettings.setJavaScriptEnabled(true) |
Allows pages to execute JavaScript |
WebSettings.setJavaScriptCanOpenWindowsAutomatically(true) |
JavaScript can call window.open() |
WebSettings.setSupportMultipleWindows(true) |
Popups are rendered in new WebViews |
ViewGroup.addView() |
Adds a new view to the top of a ViewGroup |
WebChromeClient.onCreateWindow() |
Allows custom implementation of how popup creation is handled |
WebChromeClient.onCloseWindow() |
Handler for when JavaScript calls window.close() or other window close events |
Not all settings need to be set in order to deem an application vulnerable. Each setting is potentially dangerous on its own, but even more so when combined with others. We’ll explore how attacks make use of vulnerabilities brought about by misconfiguration.
Attacks
For the following examples, we’ll assume this page structure is loaded into a WebView:
- Parent page is loaded into a WebView via the
WebView.loadData()
orWebView.loadData()
family of methods. - This parent page embeds an
<iframe>
from a trusted sourcehttps://trusted.com
. -
https://trusted.com
embeds an<iframe>
from an untrusted sourcehttps://ads.com
. -
https://ads.com
may (un)intentionally serve up a malicious<iframe>
, depending on the ad content.
Note
For max attack success, we’ll assume that the malicious ad does not retrieve frame contents from a remote url, but instead uses a data URL. More on this later.
Info
<iframe>
.
Navigation Attack
This simple attack capitalizes on WebView’s lack of navigation elements. On click, a link redirects the top frame to a malicious page. An untrusted<iframe>
could embed a link that navigates the top most frame to a malicious page:
Once clicked, the WebView is redirected with no clear indication. The user is none the wiser.
Privileged Navigation Attack
In addition to the navigation attack, which applies to all browsers, Android is vulnerable to a variant that can bypass sandbox _top
navigation restrictions if the <iframe>
is allowed to create popups (no sandbox, or sandbox sets allow-popups
).
If a frame opens a popup, Android will always try to select a WebView to render the popup. If SupportMultipleWindows
is set to false
, then no window is created for the popup. Therefore, Android selects the current WebView essentially navigating the top view anyway.
Warning
JavaScriptEnabled
and
JavaScriptCanOpenWindowsAutomatically
are both
true
, then the frame can also create a popup with
window.open()
or
showModalDialog()
Overlay Attack
Like the privileged navigation attack, an overlay attack takes advantage of Android’s ViewGroup renderingmechanics and WebView misconfiguration. A WebView is susceptible if:
-
SupportMultipleWindows
is set totrue
.
and/or
-
WebChromeClient
is attached to the WebView. -
onCreateWindow()
is overwritten , utilizingViewGroup.addView()
without an index (or withindex = -1
).
By default, whenever a popup is created and SupportMultipleWindows
is true
, Android will create a new WebView and add it to the same parent ViewGroup as the current WebView. It’ll become the last child of the parent. When Android renders views within a ViewGroup, it starts by drawing the first child. It then iterates through the ViewGroup’s children, rendering each view on top of the last. Because the popup WebView is the last child of the ViewGroup, it’ll be the topmost rendered view. It’s the only thing the user can see. A misbehaving iframe only needs to create a popup!
Closure Attack
What if the app uses ViewGroup.addView(view, 0)
as part of it’s onCreateWindow
handler? This is a mitigation for overlay attacks, but the app could still be in danger. If WebChromeClient.onCloseWindow()
is overwritten and JavaScriptEnabled
is true
, then the app is susceptible to closure attacks. They work like this:
- Frame creates a popup. Android creates and appends a new WebView containing the popup to the ViewGroup.
- Popup calls
window.close()
on the original parent frame.onCloseWindow()
has a naive implementation—it doesn’t check whether the parent WebView is being closed, and closes it anyway. - Parent WebView is removed from ViewGroup. Popup WebView is all that remains.
- The user only sees the popup. The UI has been hijacked.
Origin Hiding
So far, all previous attacks required a user to interact with a malicious element. Because of the same-origin policy (SOP) , even if JavaScript is enabled, none of the malicious frames are able to automatically navigate the _top
frame. That would require both frames share the same origin.
Origins are equivalent whenever their protocol, host, and port match. Two null
origins are also equivalent…but when is an origin null
? According to the HTML specification, browsers are required to treat data URL origins as opaque values. This is handy in instances where media needs to be loaded without violating the SOP. In summary, if the parent frame has a null
origin, then any child frame with a null
origin is part of the same origin, and is no longer in violation of the SOP.
For general browsing, it’s rare to find a legitimate use case where a parent page needs be loaded in via a data URL. However, in an Android application it’s acceptable to initialize a WebView with an inline HTML snippet then to retrieve it from a remote URL.
Consider this example:
String html = "<html><body>My Widget <iframe src=\"https://trusted.com\"></iframe></body></html>"; String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING); webView.loadData(encodedHtml, "text/html", "base64");
webView
is initialized with an HTML snippet describing a simple widget which pulls in an <iframe>
from a trusted site. Because webView
was initialized with inline data, the parent frame’s origin is null
. Therefore, any child frame sourced from a data url that trusted.com
or it’ its children produce will have the same origin as the top frame. Any child null
origin child frame is essentially granted full control .
Info
JavaScriptEnabled
is
true
in the parent WebView
Frame Hijacking
If an <iframe>
has full control over it’s parent, the simplest thing to do with this power is to navigate the top frame to a malicious page. Since WebView does not make it apparent when navigation occurs, phishing pages become much more convincing.
Let’s assume that trusted.com
embeds <iframe src="https://ads.com>
. Unbeknownst to trusted.com
, ads.com
is hosting a malicious ad. The malicious ad wants to navigate the parent to evil.com
. The malicious ad is running inside the ads.com
frame, so it’s origin is https://ads.com
. According to the SOP, it can’t navigate the top parent. What it can do, however, is create another child frame from a data URL. This child frame shares the same origin with the top frame, so it can do whatever it likes!
First, let’s look at the source of this malicious child frame:
<html> <body> <script>top.window.location = "https://evil.com";</script> </body> </html>
It is then converted to a base64 data URL:
data:text/html;base64,PGh0bWw+Cjxib2R5PgoJPHNjcmlwdD50b3Aud2luZG93LmxvY2F0aW9uID0gImh0dHBzOi8vZXZpbC5jb20iOzwvc2NyaXB0Pgo8L2JvZHk+CjwvaHRtbD4=
Then the malicious ad embeds it as an <iframe>
:
<html> <body> <h1>I serve ads!</h1> <iframe src="data:text/html;base64,PGh0bWw+Cjxib2R5PgoJPHNjcmlwdD50b3Aud2luZG93LmxvY2F0aW9uID0gImh0dHBzOi8vZXZpbC5jb20iOzwvc2NyaXB0Pgo8L2JvZHk+CjwvaHRtbD4="></iframe> </body> </html>
As soon as this ad loads, the parent frame is navigated to evil.com
automatically. Here’s what it looks like slightly slowed down. In this example the malicious ad hijacks the parent frame and loads a Facebook phisher :
Message Forgery
Consider the case where the parent frame needs to communicate with a trusted child frame via thepostMessage
API
. The parent issues a message like the following: `
window.frames[0].postMessage("Hello from parent!", "https://trusted.com")`;
The trusted.com
frame listens for messages. It knows the parent frame has a null
origin, so it checks for this whenever it receives a message and only acts if the message comes from an expected origin:
window.onmessage = function(event) { if (event.origin === "null") { // Do a privileged action } }
With this scheme, ads.com
may not postMessage()
to trusted.com
because any message sent will have an unacceptable https://ads.com
origin. However, as described earlier, a malicious ad can embed a child frame with a null
origin. Similar to frame hijacking, the child frame effectively becomes the parent frame. If the parent can communicate with trusted.com
, then so can the child. This could be bad news if the trusted frame implements sensitive functionality.
Native Bridge Hijacking
The primary purpose of a WebView is to present a native Android interface served from the web. Compared to native applications, web pages are limited in how they can interact with the client device. Missing native functionality could be jarring to an end user who may not be aware they’re viewing a web page. In order to bridge this semantic gap, WebView allows an application developer to inject JavaScript interfacesgranting access to native Java objects within the app. If used carelessly, this functionality could allow privileged access to native functionality.
In the example diagram, let’s assume that the app exposes some APIs to the web application:
createNotification() getHistory() getCredential()
Note
I don’t know why an app might surface this functionality to a web view, but just go with it
Each method does origin checking, but clearly this is insufficient. Here the parent frame creates a notification. The native bridge allows it because it expects a null
origin. Next, “for better ad personalization”, the ads.com
frame tries to get complete browser history. The bridge rejects it, citing an unacceptable origin. Unfortunately, because It’s malicious child shares the null
origin, the native bridge allows it to retrieve the credential it’s after!
Alternatives
There’s no doubting WebView’s utility. It facilitates rapid development, encourages cross-platform consistency, and could be used as a powerful temporary stopgap on its own. But as we have seen, if implemented incorrectly, it could greatly increase an application’s vulnerable surface area. Google realizes this and provides more secure alternatives.
Chrome Custom Tabs
If you simply want to render a view from the web, and this view may redirect users outside your domain, opt for Chrome Custom Tabs . It’s a robust solution which addresses some of the design flaws explored above. Some features to highlight :
- A toolbar! Users know when navigation occurs. The application can even register a navigation callback before external navigation occurs.
- Shared sessions and cookie jar with the user’s default browser.
- Pre-warming in the background for pages that a user is likely to visit
Trusted Web Activities
If full screen web content is a must, and you don’t need to mix native and web components, then Trusted Web Activities (TWA) are the recommended approach. They verify that the page being loaded is in fact what the application expects. If a loaded page fails verification, the app falls back to showing Chrome Custom Tabs, making it clear that an external navigation occurred. If the application requires multiple origins, TWA has you covered
Conclusion
If you need to serve up content from the web for your application, considering using trusted alternatives. If you absolutely must use a WebView, be wary of how you configure settings. Make sure all untrusted content is sandboxed.
This article summarizes findings from the excellent DCV paper presented at USENIX 2019. Not discussed is the automated vulnerability scanning tool they built, which they used to survey 17,000 of the most popular apps on the Google Play store. Of these, 4358 were found to be potentially vulnerable including Facebook, Instagram, Skype, Kayak, and other leading applications. I highly recommend you read it for yourself!
Of course, If you’ve got feedback for me, I’m only a tweet away :blush:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Mechanics of Web Handling
David R. Roisum
This unique book covers many aspects of web handling for manufacturing, converting, and printing. The book is applicable to any web including paper, film, foil, nonwovens, and textiles. The Mech......一起来看看 《The Mechanics of Web Handling》 这本书的介绍吧!