WebView使用漏洞
WebView 中,主要漏洞有三类:
1 任意代码执行漏洞
JS 调用Android 代码是通过addJavascriptInterface 接口进行对象映射。
1.1 漏洞产生的原因
public class AndroidJS extends Object {
@JavascriptInterface
public void hello(String msg) {
System.out.println("JS调用了Android的hello方法");
}
}
webView.addJavascriptInterface(new AndroidJS(), "test");
function callAndroid(){
test.hello("js调用了android中的hello方法");
}
参数1 :Android 的本地对象 参数2 :JS 的对象。通过对象映射将Android 中的本地对象和JS 中的对象进行关联,从而实现JS 调用Android 的对象和方法。
漏洞产生原因是:当JS 拿到Android 这个对象后,就可以调用这个Android 对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。如可以执行命令获取本地设备的SD 卡中的文件等信息从而造成信息泄露
具体获取系统类的描述(结合Java 反射机制):Android 中的对象有一公共的方法——getClass() ,该方法可以获取到当前类类型Class ,该类有一关键的方法——Class.forName ,该方法可以加载一个类(可加载java.lang.Runtime 类),而该类是可以执行本地命令的。
以下是攻击的JS 核心代码:
function execute(cmdArgs) {
for (var obj in window) {
if ("getClass" in window[obj]) {
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime")
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
}
}
}
当一些APP 通过扫描二维码打开一个外部网页时,攻击者就可以执行这段JS 代码进行漏洞攻击。
1.2 解决方案
在Android 4.2 版本之后,Google 在Android 4.2 版本中规定对被调用的函数以@JavascriptInterface 进行注解从而避免漏洞攻击。
Android 4.2 版本之前,采用拦截prompt() 进行漏洞修复。 具体如下:
每次当WebView 加载页面前加载一段本地的JS 代码,原理是:
- 让
JS 调用一Javascript 方法:该方法是通过调用prompt 把JS 中的信息(含特定标识,方法名称等)传递到Android 端; - 在
Android 的onJsPrompt 中 ,解析传递过来的信息,再通过反射机制调用Java 对象的方法,这样实现安全的JS 调用Android 代码;(关于Android 返回给JS 的值,可通过prompt 把Java 中方法的处理结果返回到JS 中)
javascript:(function JsAddJavascriptInterface_() {
if (typeof(window.jsInterface)!='undefined') {
console.log('window.jsInterface_js_interface_name is exist!!');
} else {
window.jsInterface = {
onButtonClick:function(arg0) {
return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]}));
},
onImageClick:function(arg0,arg1,arg2) {
return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]}));
},
};
}
})()
2 密码明文存储漏洞
WebView 默认开启密码保存功能:webView.setSavePassword(true) 。开启后,在用户输入密码时,会弹出提示框:询问用户是否保存密码;如果选择”是”,密码会被明文保到 /data/data/com.package.name/databases/webview.db 中,这样就有被盗取密码的危险。
关闭密码保存提醒:webSettings.setSavePassword(false)
3 域控制不严格漏洞
如下代码:
public class WebViewActivity extends Activity {
private WebView webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webview);
webView = (WebView) findViewById(R.id.webView);
Intent i = getIntent();
String url = i.getData().toString();
webView.loadUrl(url);
}
}
在清单文件中将WebViewActivity 设置android:exported = "true" 属性,表示当前Activity 是否可以被另一个Application 的组件启动。即A 应用可以通过B 应用导出的Activity 让B 应用加载一个恶意的file 协议的url ,从而可以获取B 应用的内部私有文件,从而带来数据泄露威胁。
当其他应用启动可以允许外部调用的Activity 时, intent 中的data 直接被当作url 来加载(假定传进来的url 为 file:///data/local/tmp/attack.html ),其它APP 通过使用显式ComponentName 或者其他类似方式就可以很轻松的启动该 WebViewActivity 并加载恶意url 。
对于不需要使用file 协议的应用,禁用file 协议:
setAllowFileAccess(false);
对于需要使用file 协议的应用,禁止file 协议加载JavaScript :
setAllowFileAccess(true);
if (url.startsWith("file://") {
setJavaScriptEnabled(false);
} else {
setJavaScriptEnabled(true);
}
|