WebView is a view that allows an application to load web pages within it. Internally it uses web rendering engines such as Webkit. The Webkit rendering engine was used prior to Android version 4.4 to load these web pages. On the latest versions (after 4.4) of Android, it is done using Chromium. When an application uses a WebView, it is run within the context of the application, which has loaded the WebView. To load external web pages from the Internet, the application requires INTERNET permission in its AndroidManifest.xml
file:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Using WebView in an Android app may pose different risks to the application depending upon the mistakes the developers make.
When an Android application uses a WebView with user controlled input values to load web pages, it is possible that users can also read files from the device in the context of the target application.
Following is the vulnerable code:
public class MainActivity extends ActionBarActivity {
EditText et;
Button btn;
WebView wv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = (EditText) findViewById(R.id.et1);
btn = (Button) findViewById(R.id.btn1);
wv = (WebView) findViewById(R.id.wv1);
WebSettings wvSettings = wv.getSettings();
wvSettings.setJavaScriptEnabled(true);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
wv.loadUrl(et.getText().toString());
}
});
}
}
When this code is run, the following is what appears on the screen:
Now, entering a website URL will result in opening the web page. I am entering some sample URL as shown in the following figure:
Basically, this is the functionality of the application. But, an attacker also read files using the scheme file://
as shown in the following figure:
As you can see in the preceding figure, we are able to read the contents from SD card. This requires READ_EXTERNAL_STORAGE
permission in the app's AndroidManifest.xml
file. This app already has this permission:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
Additionally, we can read any file that the app has access to, such as Shared Preferences.
Validating the user input as shown in the following code snippet will resolve the issue:
public class MainActivity extends ActionBarActivity { EditText et; Button btn; WebView wv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et = (EditText) findViewById(R.id.et1); btn = (Button) findViewById(R.id.btn1); wv = (WebView) findViewById(R.id.wv1); WebSettings wvSettings = wv.getSettings(); wvSettings.setJavaScriptEnabled(true); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String URL = et.getText().toString(); if(!URL.startsWith("file:")) { wv.loadUrl(URL); } else { Toast.makeText(getApplicationContext(), "invalid URL", Toast.LENGTH_LONG).show(); } } }); } }
Earlier, the application was receiving the user input and processing it without any further validation. Now, the preceding piece of code is checking if the user entered input starts with the file
: scheme as shown in the following line. If yes, it will throw an error.
if(!URL.startsWith("file:")) {
Care has to be taken when applications make use of the addJavaScriptInterface()
method as this will provide a bridge between native Java code and JavaScript. This means your JavaScript can invoke native Java functionality. An attacker who can inject his own code into the WebView can abuse these bridge functions.
One of the popular vulnerabilities related to this method is CVE-2012-6636. You may read more about this issue at the following link:
http://50.56.33.56/blog/?p=314
Aside to this, it is a common mistake by developers to ignore SSL warnings. A simple search at the stack overflow about WebView SSL errors will result in the following code snippet:
@Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { handler.proceed(); }
The preceding code snippet will ignore any SSL errors, thus leading to MitM attacks.