Android安全问题-网络传输

qpxj8382 8年前
   <h2><strong>前言</strong></h2>    <p>Android开源,开源就意味着无线可能和无线的不安全。现在(2016)市面上的所有Android安全方法基本上有以下几种:</p>    <p>1.代码混淆。</p>    <p>2.so处理重要逻辑。</p>    <p>3.加壳</p>    <p>这些都是在客户端做的处理,然而,如果破解客户端能获取的利益大于破解的难度,那么基于开源的Android基本还是会被"破解大军"进行"三光政策"的。既然都会被破解,那还做这些做什么呢?这就是我之前文章说的,利益和难度的取舍。当我们做了以上3部后,就已经阻绝绝大部分的"破解军",剩下的哪些顶尖人物怎么办呢?现在我的处理方法是放在服务端。</p>    <h2><strong>问题</strong></h2>    <p>要解决问题,首先要有问题,那么对于客户端来说什么是危险的呢?举个栗子,当用户注册的时候,如果明文传输就有可能被拦截到,泄漏用户密码的问题。正对这个问题,我来叙述一下自己的解决方案,顺便把这篇文章的重点带出来。</p>    <h2><strong>解决</strong></h2>    <p>问题:用户注册和服务端交互的信息有可能被拦截,导致账户等信息泄露。</p>    <p><strong>方法1</strong></p>    <p>将用户密码进行MD5后再传递。</p>    <p>这种方法也就保证了我们自己也无法知道用户的密码是什么。即使被拦截,破解军获取到这段信息也无法得知密码是什么。</p>    <p>PS:这种方法是可取的,但是如果用户的密码比较简单,那也是可以通过暴力破解出来的。所以MD5的方法比较适合用来确保数据的正确性,而不适合作为数据的保密处理。</p>    <p><strong>方法2</strong></p>    <p>使用特殊算法进行加密后在传递。</p>    <p>这种方法可以确保即使被拦截到信息,在不知道我们算法的前提下,破解军也无法获取有用信息。</p>    <p>不过这里有两个问题,第一是算法在破解后很容易查询到,即使是存放在so文件中。第二是这种自己定义算法对性能的要求可能比较高,毕竟我们又不是数学专家。</p>    <p>当然为了更坚固的堡垒,提高破解军的成本,该方法是可以结合使用的。</p>    <p><strong>方法3</strong></p>    <p>使用AES加密报文后在传递。</p>    <p>这种方法和方法2类似,只是AES是当下确定能很好加密数据,且很难暴力破解的方案。当然加密就要解密,而AES的加密和解密使用的通一个key值。那么就需要客户端存储一个key值,既然该key值存在客户端,那么破解的可能性就很大了。针对这个问题,有一个弯路可以考虑,那就是隐藏key值。</p>    <p>这里就记录一下隐藏key值的小故事,该方法不单是隐藏key值,也可以隐藏很多东西,增加破解的成本。</p>    <p>好,假设我们使用了AES加密,那么就有一个key值,那么我们应该怎么存这个key在客户端呢?</p>    <p>方法基本有以下这几种:</p>    <p>SharedPreferences</p>    <p>Java硬编码</p>    <p>NDK保存在so</p>    <p>发现,除了NDK的方法有点难度,其它两种基本都是新手破解军都能搞定的事,那么怎么办呢?那我就给他来个大杂烩别(年轻人啊)。首先我把key分成了4份。</p>    <p>key = "whitelaning";</p>    <p>key1 = "wh";</p>    <p>key2 = "ite";</p>    <p>key3 = "lan";</p>    <p>key4 = "ing";</p>    <p>当需要使用key的时候分别获取4段可以值合并后才能得到真正的key。</p>    <p><strong>key1写在string.xml中</strong></p>    <p>mContext().getResources().getString(R.string.something1); 。</p>    <p>ps:为什么叫something1呢,年轻人不懂事...</p>    <p><strong>key2写在AndroidManifest.xml中</strong></p>    <p><meta-data android:name="something2" android:value="ite"/> 。</p>    <p><strong>key3写在so文件中。</strong></p>    <pre>  <code class="language-java">#include "com_jni_JNIUtils.h"  JNIEXPORT jstring JNICALL Java_com_jni_JNIUtils_getString          (JNIEnv *env, jobject obj) {      return (*env)->NewStringUTF(env, "something3");  }    //---------------------------------------    key3 = new JNIUtils().getString();</code></pre>    <p><strong>key4写在assets的文件中。</strong></p>    <p>Context.getAssets().open(“something4.txt”)</p>    <p>然后...破解的难度提高了,而且也把以后的开发者逼疯了...哈哈...(弃用)</p>    <p><strong>方法4(使用中)</strong></p>    <p><strong>客户端 --> 服务端</strong></p>    <p>客户端使用随机生成的AES密钥加密传输数据,使用RSA公钥加密AES的密钥。</p>    <p>服务端使用RSA私钥解密出AES的密钥,再使用AES的密钥解密加密的数据。</p>    <p><strong>服务端 --> 客户端</strong></p>    <p>服务端使用RSA解密出AES的密钥后,使用该AES密钥解密数据,然后进行业务处理。业务处理完毕后,使用该AES密钥对数据进行加密,返回给客户端。</p>    <p>客户端接收到返回数据后,使用之前请求时随机生成的AES密钥进行解析,然后废弃该AES密钥。</p>    <p>以上就是一次完整的请求交互过程,当然省略了一些细节上的处理和具体业务。比如数据应该使用MD5来验证数据的完整性,接口验证等等。</p>    <p>方法4有点类似 SSL/TLS 协议握手的原理,当然因为Android是开源的,没必要完全按照 SSL/TLS 协议来实现,毕竟做安全问题的时候,我都是默认我的源码被盗了的情况下去做的。</p>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/84636b4b21d2</p>    <p> </p>