在IM中经常有嵌套网页的功能,主流都是用 Android的WebView 实现的,但是 WebView 使用过程中存在许多漏洞,容易造成用户数据泄露等等危险,而很多人往往会忽视这个问题。本文将介绍 Android WebView的使用漏洞 及其修复方式。
1. 类型
WebView中,主要漏洞有三类:
2. 具体分析
2.1 域控制不严格漏洞
2.1.1 问题分析
先看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 安全性的影响:
- setAllowFileAccess()
- setAllowFileAccessFromFileURLs()
- setAllowUniversalAccessFromFileURLs()
1. setAllowFileAccess()
// 设置是否允许 WebView 使用 File 协议 webView.getSettings().setAllowFileAccess(true); // 默认设置为true,即允许在 File 域下执行任意 JavaScript 代码
使用 file 域加载的 js代码能够使用进行同源策略跨域访问,从而导致隐私信息泄露
- 同源策略跨域访问:对私有目录文件进行访问
- 针对 IM 类产品,泄露的是聊天信息、联系人等等
- 针对浏览器类软件,泄露的是cookie 信息泄露。
如果不允许使用 file 协议,则不会存在上述的威胁;
webView.getSettings().setAllowFileAccess(true);
但同时也限制了 WebView 的功能,使其不能加载本地的 html 文件,如下图:
移动版的 Chrome 默认禁止加载 file 协议的文件
解决方案:
对于不需要使用 file 协议的应用,禁用 file 协议;
setAllowFileAccess(false);
对于需要使用 file 协议的应用,禁止 file 协议加载 JavaScript。
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代码为:
// 通过该代码可成功读取 /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 的内容
解决方案:设置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 的延时执行和将当前文件替换成指向其它文件的软链接就可以读取到被符号链接所指的文件。具体攻击步骤:
1. 把恶意的 js 代码输出到攻击应用的目录下,随机命名为 xx.html,修改该目录的权限;
2. 修改后休眠 1s,让文件操作完成;
3. 完成后通过系统的 Chrome 应用去打开该 xx.html 文件
4. 等待 4s 让 Chrome 加载完成该 html,最后将该 html 删除,并且使用 ln -s 命令为 Chrome 的 Cookie 文件创建软连接
注:在该命令执行前 xx.html 是不存在的;执行完这条命令之后,就生成了这个文件,并且将 Cookie 文件链接到了 xx.html 上。
于是就可通过链接来访问 Chrome 的 Cookie
Google 没有进行修复,只是让Chrome 最新版本默认禁用 file 协议,所以这一漏洞在最新版的 Chrome 中并不存在
但是,在日常大量使用 WebView 的App和浏览器,都有可能受到此漏洞的影响。通过利用此漏洞,容易出现数据泄露的危险
如果是 file 协议,禁用 javascript 可以很大程度上减小跨源漏洞对 WebView 的威胁。
但并不能完全杜绝跨源文件泄露。
例:应用实现了下载功能,对于无法加载的页面,会自动下载到 sd 卡中;由于 sd 卡中的文件所有应用都可以访问,于是可以通过构造一个 file URL 指向被攻击应用的私有文件,然后用此 URL 启动被攻击应用的 WebActivity,这样由于该 WebActivity 无法加载该文件,就会将该文件下载到 sd 卡下面,然后就可以从 sd 卡上读取这个文件了
最终解决方案
对于不需要使用 file 协议的应用,禁用 file 协议;
// 禁用 file 协议; setAllowFileAccess(false); setAllowFileAccessFromFileURLs(false); setAllowUniversalAccessFromFileURLs(false);
对于需要使用 file 协议的应用,禁止 file 协议加载 JavaScript。
// 需要使用 file 协议 setAllowFileAccess(true); setAllowFileAccessFromFileURLs(false); setAllowUniversalAccessFromFileURLs(false); // 禁止 file 协议加载 JavaScript if (url.startsWith("file://") { setJavaScriptEnabled(false); } else { setJavaScriptEnabled(true); }