Android开发常见安全漏洞总结

目录

    • WebView组件远程代码执行漏洞
      • addJavascriptInterface接口
      • 解决方案
      • searchBoxJavaBridge_接口
      • 解决方案
      • accessibility 和 accessibilityTraversal
      • 解决方案
    • WebView跨域访问漏洞
      • 解决方案
    • WebView组件忽略SSL证书验证错误漏洞
      • 解决方案
    • WebView密码明文保存漏洞
      • 解决方案
    • 本地端口开放越权风险
      • 解决方案
    • Content Provider目录遍历漏洞
      • 解决方案
    • SQL注入漏洞
      • 解决方案
    • ZIP文件解压目录遍历风险
      • 解决方案
    • PendingIntent包含隐式Intent风险
      • 解决方案
    • 剪贴板敏感信息泄露风险
      • 解决方案
    • 随机数使用不当漏洞
      • 解决方案
    • SharedPreference全局读写漏洞
      • 解决方案
    • 数据库全局读写漏洞
      • 解决方案
    • 动态加载DEX文件风险
      • 解决方案
    • 应用数据任意备份风险
      • 解决方案
    • 程序可被任意调试风险
      • 解决方案

WebView组件远程代码执行漏洞

addJavascriptInterface接口

Android API level 16以及之前的版本存在远程代码执行安全漏洞,该漏洞源于程序没有正确限制使用WebView.addJavascriptInterface方法,远程攻击者可通过使用Java Reflection API利用该漏洞执行任意Java对象的方法,简单的说就是通过addJavascriptInterface给WebView加入一个JavaScript桥接接口,JavaScript通过调用这个接口可以直接操作本地的JAVA接口。

mWebView.getSettings().setJavaScriptEnabled(true);  
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");  

我们向WebView注册一个名叫“jsInterface”的对象,然后在JS中可以访问到jsInterface这个对象,就可以调用这个对象的一些方法,最终可以调用到Java代码中,从而实现了JS与Java代码的交互。

JS中可以遍历window对象,找到存在“getClass”方法的对象的对象,然后再通过反射的机制,得到Runtime对象,然后调用静态方法来执行一些命令。

核心代码如下:

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);  
        }  
    }  
} 

解决方案

  1. Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击
  2. Android 4.2版本之前采用拦截prompt()进行漏洞修复。 详见

searchBoxJavaBridge_接口

在Android 3.0以下,Android系统会默认通过searchBoxJavaBridge_的Js接口给 WebView 添加一个JS映射对象:searchBoxJavaBridge_对象。

解决方案

删除默认添加的"searchBoxJavaBridge_"。

mWebView.removeJavascriptInterface("searchBoxJavaBridge_");  

accessibility 和 accessibilityTraversal

此漏洞原理与searchBoxJavaBridge_接口远程代码执行相似,均为未移除不安全的默认接口,不过此漏洞需要用户启动系统设置中的第三方辅助服务,利用条件较复杂。

解决方案

与searchBoxJavaBridge_的解决方案类似:可以调用removeJavascriptInterface(“accessibility”) 和removeJavascriptInterface(“accessibilityTraversal”) 方法移除这两个默认接口。

WebView跨域访问漏洞

如果一个Activity可以被其他应用调起,例如声明了android:exported="true",相关WebView又开启了file域访问,同时未对file 域的路径进行严格限制所致。攻击者通过URL Scheme 的方式,可远程打开并加载恶意HTML文件,远程获取APP中包括用户登录凭证在内的所有本地敏感数据。

涉及到三个方法:

  • setAllowFileAccess

    设置是否允许WebView使用File协议,默认设置为true,即允许在File域下执行任意JavaScript代码。

  • setAllowFileAccessFromFileURLs

    设置是否允许通过 file url 加载的 Js代码读取其他的本地文件。

  • setAllowUniversalAccessFromFileURLs

    设置是否允许通过 file url 加载的 Javascript 可以访问其他的源(包括http、https等源)。

解决方案

1.file域访问为非功能需求时,手动配置setAllowFileAccessFromFileURLs或setAllowUniversalAccessFromFileURLs两个API为false。(Android4.1版本之前这两个API默认是true,需要显式设置为false)

2.若需要开启file域访问,则设置file路径的白名单,严格控制file域的访问范围,具体如下:

(1)固定不变的HTML文件可以放在assets或res目录下,file:///android_assetfile:///android_res 在不开启API的情况下也可以访问;

(2)可能会更新的HTML文件放在/data/data/(app) 目录下,避免被第三方替换或修改;

(3)对file域请求做白名单限制时,需要对“…/…/”特殊情况进行处理,避免白名单被绕过。
3.避免App内部的WebView被不信任的第三方调用。排查内置WebView的 Activity是否被导出、必须导出的Activity是否会通过参数传递调起内置的WebView等。

4.建议进一步对APP目录下的敏感数据进行保护。客户端APP应用设备相关信息(如IMEI、IMSI、Android_id等)作为密钥对敏感数据进行加密。使攻击者难以利用相关漏洞获得敏感信息。

WebView组件忽略SSL证书验证错误漏洞

Android WebView组件加载网页发生证书认证错误时,会调用WebViewClient类的onReceivedSslError方法,如果该方法实现调用了handler.proceed()来忽略该证书错误,则会受到中间人攻击的威胁,可能导致隐私泄露。

实现onReceivedSslError的处理,漏洞代码样例:

mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                handler.proceed(); // Ignore SSL certificate errors
            }
        });

如上代码在onReceivedSslError处理时没有进行cancel,还是使用了proceed(),忽略掉了发生的SSL异常。

解决方案

1.非浏览器类app,有条件的可以申请正式的ca证书,没条件的可以在客户端中添加证书,切勿信任所有证书或者忽略ssl证书认证错误。

2.浏览器 app,严格按照客户端校验服务器证书流程处理

1) 客户端需要检查证书是否过期

2) 证书签发的 CA 是否可靠

3) CA 的公钥能否正确解开服务器证书的 CA 数字签名,对证书的签名值的有效性做验证

4) 服务器证书上的域名是否和服务器的实际域名相匹配

3.重载了 onReceivedSslError 方法处理时使用 cancel 方法来停止加载 ssl 验证错误的页面,如下代码:

mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                handler.cancel(); // Ignore SSL certificate errors
            }
        });

WebView密码明文保存漏洞

在使用WebView的过程中忽略了WebView setSavePassword,当用户选择保存在WebView中输入的用户名和密码,则会被明文保存到应用数据目录的databases/webview.db中。如果手机被root就可以获取明文保存的密码,造成用户的个人敏感数据泄露。

如果代码中没有显示调用setSavePassword(false) ,默认为true。

解决方案

使用WebView.getSettings().setSavePassword(false)来禁止保存密码。

本地端口开放越权风险

Android应用通常使用PF_UNIXPF_INETPF_NETLINK等不同domain的socket来进行本地IPC或者远程网络通信,这些暴露的socket代表了潜在的本地或远程攻击面,历史上也出现过不少利用socket进行拒绝服务、root提权或者远程命令执行的案例。特别是PF_INET类型的网络socket,可以通过网络与Android应用通信,其原本用于linux环境下开放网络服务,由于缺乏对网络调用者身份或者本地调用者id、permission等细粒度的安全检查机制,在实现不当的情况下,可以突破Android的沙箱限制,以被攻击应用的权限执行命令,通常出现比较严重的漏洞。

如果没有对收到的socket和内容做任何校验检查,会绕过android各种安全机制以被攻击的应用的权限执行。某些情况下会直接导致远程命令任意执行,同理使用UDP通信使用上述逻辑的代码也会存在类似问题。

解决方案

直接传递命令字或者间接处理有敏感信息或操作时,避免使用socket实现,使用能够控制权限校验身份的方式通讯。

Content Provider目录遍历漏洞

在使用Content Provider时,将组件导出,提供了openfile接口。在使用Content Provider时,将组件导出,并且实现了OpenFile接口。由于对URI路径没有做相应过滤,导致目录遍历,造成信息泄漏以及远程代码执行问题。

public class FileProvider extends ContentProvider {


    //  重写该方法
    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
        File file = new File(getContext().getFilesDir(),uri.getPath());
        if(file.exists()){
            return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
        }
        throw new FileNotFoundException(uri.getPath());
    }
    
    ...

}


可以构造../../../../../system/etc/hostsURI路径,如果该provider导出或者设置了protect及以下权限,将会读出hosts文件的内容。如果读取了APP data目录下的文件将会导致隐私的泄漏。

解决方案

  • Provider不需要导出,请将export属性设置为false;
  • 若导出仅为内部通信使用,则设置protectionLevel=signature
  • Openfile接口不需要实现,请移除该接口的实现;
  • 若确实需要Openfile接口,请对URI中如…/,可能引发遍历的路径字符做相应过滤。

SQL注入漏洞

对数据库进行增删改查操作时,程序没有对用户的输入进行过滤,未采用参数化查询的方式,可能导致sql注入攻击。这样攻击者可以精心构造selection、projection参数等sql语句组成部分,实现在未授权的情况下从数据库获取更多的信息。

解决方案

  • Provider不需要导出,请将export属性设置为false
  • 若导出仅为内部通信使用,则设置protectionLevel=signature
  • 不直接使用传入的查询语句用于projection和selection,使用由query绑定的参数selectionArgs
  • 完备的SQL注入语句检测逻辑

ZIP文件解压目录遍历风险

由于zip允许其中的文件含有 ., /, ¥ 等特殊字符,当从不安全的来源如HTTP下载或者SDK卡获得ZIP格式文件并解压缩时,如果该ZIP文件被劫持插入恶意代码,且没有禁止ZIP目录遍历,可能导致任意代码执行。

如果解压路径中包含…/字符串,就会造成目录的遍历问题,一旦遭到中间人攻击替换下载的文件,将会导致某些恶意文件被执行。

解决方案

解压缩ZIP格式文件时,注意验证其来源和完整性,并禁止解压目录遍历,例如:

    static final int BUFFER = 512;
    static final int TOOBIG = 0x6400000; // upper limit of filesize, 100MB
    static final int TOOMANY = 1024; // upper limit of entries
    // ...
    private String validateFilename(String filename, String intendedDir) {
         File f = new File(filename);
         String canonicalPath = f.getCanonicalPath();
         File iD = new File(intendedDir);
         String canonicalID = iD.getCanonicalPath();
         if (canonicalPath.startsWith(canonicalID)) {
         return canonicalPath;
         } else {
         throw new IllegalStateException("File is outside extraction target
        directory.");
         }
    }       

PendingIntent包含隐式Intent风险

PendingIntent可以让其他APP中的代码像是运行自己APP中。PendingIntent的intent接收方在使用该intent时与发送方有相同的权限。在使用PendingIntent时,PendingIntent中包装的intent如果是隐式的Intent,容易遭到劫持,导致信息泄露。

PendingIntent可以调用以下几类组件发送intent:

getActivity(Context, int, Intent, int)
getActivities(Context, int, Intent[], int)
getBroadcast(Context, int, Intent, int)
getService(Context, int, Intent, int)

使用PendingIntent发送广播,漏洞代码样例:

    ...

    Intent intent = new Intent(
                "com.lsd.sss.action.METHOD");
        intent.addFlags(32);
        intent.putExtra("app",
        PendingIntent.getBroadcast(this, 0, intent, 0));
    ...

如上代码PendingIntent.getBroadcast,PendingItent中包含的Intent为隐式intent,因此当PendingIntent触发执行时,发送的intent很可能被嗅探或者劫持,导致intent内容泄漏。

解决方案

使用PendingIntent时,建议使用显示Intent。

剪贴板敏感信息泄露风险

同一部手机中安装的其他app,甚至是一些权限不高的app,都可以通过剪贴板功能获取密码管理器中的账户密码信息。原因是Android剪贴板的内容向任何权限的app开放,很容易就被嗅探泄密。

解决方案

避免使用剪贴板明文存储敏感信息。

随机数使用不当漏洞

影响版本:Android4.2以前版本

2013年比特币开发商在一篇博客中透露,由于Android系统存在一处关键漏洞,该平台上的比特币电子钱包很容易失窃。比特币开发商称,该漏洞影响到Android平台上的每一个比特币电子钱包应用程序,包括流行的比特币钱包(Bitcoin Wallet)、blockchain.info钱包(blockchain.info wallet)、BitcoinSpinner钱包(BitcoinSpinner Wallet)和Mycelium钱包(Mycelium Wallet)等该漏洞是由于Android系统随机生成数字串安全密钥时,对SecureRandom 类的使用方式不恰当导致的。

 SecureRandom secureRandom = new SecureRandom(new byte[] { 1, 2, 3, 4 });

这种方式会导致生成的随机数可以预测,导致后续依赖于该随机数的加密不安全。

解决方案

  • 不使用setSeed方法
  • 使用/dev/urandom或者/dev/random来初始化伪随机数生成器

SharedPreference全局读写漏洞

APP在创建SharedPreference时,将数据库设置了全局的可读权限,攻击者恶意读取SharedPreference内容,获取敏感信息。在设置SharedPreference属性时如果设置全局可写,攻击者可能会篡改、伪造内容,可以能会进行诈骗等行为,造成用户财产损失。

以下为SharedPreference全局读写的一种实现方式,漏洞代码样例:

    ...
        SharedPreferences r_preferences = getSharedPreferences("r_preferences",
                Context.MODE_WORLD_READABLE);
        SharedPreferences w_preferences = getSharedPreferences("w_preferences",
                Context.MODE_WORLD_WRITEABLE);
        SharedPreferences.Editor editor = r_preferences.edit();
        editor.putString("name", "James");
        editor.putString("password", "Gosling");
        editor.commit();
    ...

解决方案

1.用MODE_PRIVATE模式创建SharedPreference

2.避免在SharedPreference中存储明文和敏感信息

数据库全局读写漏洞

APP在创建数据库时,将数据库设置了全局的可读权限,攻击者恶意读取数据库内容,获取敏感信息。在设置数据库属性时如果设置全局可写,攻击者可能会篡改、伪造内容,可以能会进行诈骗等行为,造成用户财产损失。
以下为数据库全局读写的一种实现方式,漏洞代码样例:

    ...
        try {
            SQLiteDatabase rdb = openOrCreateDatabase("all_r_db",
                    Context.MODE_WORLD_READABLE, null);
            SQLiteDatabase wdb = openOrCreateDatabase("all_w_db",
                    Context.MODE_WORLD_WRITEABLE, null, null);
        } catch (SQLiteException e) {
            e.printStackTrace();
        }
    ...

解决方案

1.用MODE_PRIVATE模式创建数据库

2.使用sqlcipher等工具加密数据库

3.避免在数据库中存储明文和敏感信息

动态加载DEX文件风险

Android系统提供了一种类加载器DexClassLoader,在运行时动态加载执行包含在JAR或APK文件内的DEX文件。动态加载DEX文件的安全风险源于:Anroid4.1之前的系统版本允许APP动态加载存储在可以被其他应用读写的目录中的DEX文件(如sdcard),因此不能够保护应用免遭恶意代码的劫持注入。

如果APP外部加载的DEX文件没做完整性校验,所加载的DEX易被恶意应用所劫持或者代码注入。一旦APP外部的DEX被劫持,将会执行攻击者的恶意代码,进一步实施欺诈、获取账号密码或其他恶意行为。

直接加载可以任意读写的dex、apk文件,漏洞代码样例:

...
String apkPath = "/sdcard/dynamicload.apk";
DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,
                this.getClass().getClassLoader());
...


代码中直接从SDCARD上读取,并且没有对加载的文件进行校验,这种做法很容易遭到劫持。

解决方案

1.加载的APK、DEX文件时要进行合理的校验

2.动态加载的文件应该存储在APP是私有目录,防止权限泛滥导致被篡改

应用数据任意备份风险

当AndroidManifest.xml配置文件中没有有设置allowBackup标志(默认为true)或将allowBackup标志设置为true时,应用程序的数据可以被任意备份和恢复,恶意攻击者可以通过adb工具备份复制应用程序的数据。

解决方案

在AndroidManifest.xml文件中设置application的属性 android:allowBackup=“false”。

程序可被任意调试风险

在AndroidManifest.xml文件中 android:debuggable 被设置为 true时,应用程序的Java层代码可以被调试,存在潜在的风险。

解决方案

在AndroidManifest.xml文件中设置application的属性 android:debuggable=“false”,或者使用release模式编译发布的应用程序。

你可能感兴趣的:(android开发)