移动应用安全开发指南(Android)--完结篇(http://www.bubuko.com/infodetail-577312.html)

一、认证和受权

概述android

 

 

认证是用来证实用户身份合法性的过程,受权是用来证实用户能够合法地作哪些事的过程,这两个过程通常是在服务器端执行的,但也有的APP出于性能提高或用户体验等缘由,将其作在客户端完成,由此致使客户端绕过等问题。web

安全准则算法

 

 

  1. 在客户端作认证和受权是很难保证安全的,因此应该把认证和受权作在服务器端。若是确实有特殊的需求,能够和安全工程师进行沟通作单一case分析。
  2. 尽量避免在设备上存储用户名和密码,可使用登陆认证后得到的token进行鉴权(同时注意控制token的有效期)。

详细描述安全

 

 

Item B的典型应用场景是实现自动登陆,用户登陆认证后在本地存储用户的认证token,用户退出程序时认证token不会被删除,再次打开程序时可直接携带认证token获取数据,同时为了保证了足够的安全性,能够根据当前终端硬件信息产生独立密钥,而后对token进行加密。具体设计参考附录8。服务器

备注web安全

 

 

在本地存储对称加密后的用户口令密文,在登陆时还原出明文也是实现自动登陆的一种可选方案,但其安全性偏低,故在当今已并不是一种主流的作法。性能

     

二、加密解密

概述this

 

 

开发人员在移动应用中一般会对敏感数据进行加密处理,可是使用不当有可能让其保护强度削弱,甚至大打折扣,所以,正确的选择加解密算法显得很是重要。编码

安全准则加密

 

 

  1. 在不须要还原用户明文密码的场景使用哈希算法,在须要还原用户明文密码的场景下使用对称加密算法,而且始终优先选择使用哈希算法。
  2. 使用目前主流的安全加密算法,好比哈希算法可使用sha256,对称加密算法可使用AES128/256,不使用过期的不安全算法,好比RC四、RC五、MD5和SHA1。
  3. 不使用自定义的加密算法。
  4. 密文和密钥不要放在同一文件或同一目录内,应分开存放。
  5. 密钥不可硬编码在代码里面。

详细描述

 

 

使用AES128加密算法时,密钥应同时知足长度(128bit)和复杂度的要求,建议使用安全的随机数发生器产生安全的密钥,Sha256哈希算法和AES128对称加密算法的使用方法请参考附录1。

备注

 

 

注意:在某些不牵涉敏感数据的场景下,不安全的哈希算法仍然是可用的,好比用于校验文件或数据的完整性。

     

 

 

 

三、安全配置和部署

概述

 

 

安全开发能够大大下降移动应用的安全风险,一样地,安全的配置和部署可让风险降到最低。

安全准则

 

 

  1. 确保使用的第三方组件是从官方下载的,而且是最新版本的。
  2. 为应用程序申请最小的Permissions,若是用不上就不要申请。
  3. 应用和补丁在发布前建议进行病毒和恶意代码检测。
  4. 为敏感数据输入界面提供防截屏措施,对抗木马。

详细描述

 

 

在Activity的onCreate()方法的初始化部分加入如下代码可用于防截屏:

getWindow().addFlags(WindowManager.LayoutParams. FLAG_SECURE);

备注

 

 

非官方的库可能被植入恶意代码,而使用最新版本的库(非beta版)能够下降漏洞存在的可能性。

     

 

 

 

四、应用加固

概述

 

 

一般一个应用发布后可能会面临如下风险:

A.  应用被别人解包植入广告或恶意代码再重打包发布。

B.  应用被暴力破解。

C.  应用的核心关键代码逻辑被逆向。

所以,有必要在技术层面采起必定的缓解措施。

安全准则

 

 

  1. 对Java代码进行混淆,对抗反编译。
  2. 对Native代码进行加壳,对抗反汇编。
  3. 应用程序加入动态反调试方法。
  4. 应用程序加入防二次打包的方法。

详细描述

 

 

  1. 可使用proguard对Java源码进行混淆。
  2. 可使用UPX进行加壳保护,请参考《Android SO加壳指南v1.0》。

 

  1. 预先在AndroidManifest.xml文件插入android:debuggable=”false”,在程序中判断该标志位是否被篡改,此外,android SDK也提供了相关方法来检测调试器是否已链接,可在程序中随机插入检测,关键代码以下(详情参考附录10):
  2. 应用程序被篡改并重打包时一定要从新签名,签名值和原开发者的一定不同(不考虑证书丢失的状况),另外,从新编译程序classes.dex文件确定会变,所以可在程序运行时对比签名或CRC值的方法对抗重打包(参考附录11)。

备注

 

 

以上方案参考《Android软件安全与逆向分析》一书,但只能提供比较基本的保护措施,若是要进一步提升攻击者的攻击门槛,建议使用第三方的定制方案。

     

 

 

 

五、MISC(其它)

概述

 

 

本项做为其它移动客户端项的进一步补充。

安全准则

 

 

  1. 关键性业务逻辑代码应放在native代码实现,除此之外,尽可能使用android SDK作开发,减小对native代码的依赖(native代码通常采用C/C++编写,容易出现缓冲区溢出等漏洞)。
  2. 尽可能少用动态加载的方式执行代码(好比使用DexClassLoader),若是须要从外部存储动态加载可执行文件或类文件(好比使用DexClassLoader),应通过严格的文件完整性验证。

详细描述

 

 

文件完整性校验方案(参考附录9):

  1. 对待动态加载的可执行文件或类文件进行哈希计算,并与存储在服务器端的正确的哈希值进行对比,若是一致则表示文件未被篡改过,不然拒绝执行加载。

备注

 

 

存放在外部存储的文件是可公共访问的,可能会被其它恶意进程篡改,动态加载这些文件就有可能致使恶意代码执行。

     

 

 

 

六、服务器端的安全

概述

 

 

大部分移动应用并不是一个独立的单机程序,须要在服务器的支撑下完成一系列的功能,而服务器通常是以web API、web service等方式为移动客户端提供服务,所以,也一样存在web应用的安全问题,而这部分问题牵涉面广而复杂,没法在单独的item内进行描述,可参考《web安全开发指南》

安全准则

 

 

请参考《web安全开发指南》

详细描述

 

 

 

备注

 

 

 

 

 

 

十、Android动态反调试方案:

10.一、检测AndroidManifest.xml的调试标志位是否被篡改:

if((getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE) != 0){

System.exit(1);//使程序强制退出

}

注意:使用此方法时必须预先在AndroidManifest.xml设置android:debuggable=”false”,攻击者要尝试调试应用时颇有可能去修改该参数,于是此手法可用于作动态反调试检测。

10.二、检测应用程序是否链接调试器:

if(android.os.Debug.isDebuggerConnected()){

System.exit(1);

}

十一、防止二次打包方案:

11.一、签名检查

public class getSign {

public static int getSignature(PackageManager pm , String packageName){

PackageInfo pi = null;

int sig = 0;

Signature[]s = null;

try{

pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);

s = pi.signatures;

sig = s[0].hashCode();//s[0]是签名证书的公钥,此处获取hashcode方便对比

}catch(Exception e){

handleException();

}

return sig;

}

}

主程序代码参考:

pm = this.getPackageManager();

int s = getSign.getSignature(pm, "com.hik.getsinature");

if(s != ORIGNAL_SGIN_HASHCODE){//对比当前和预埋签名的hashcode是否一致

System.exit(1);//不一致则强制程序退出

}

11.二、CRC校验保护

private boolean checkcrc(){

boolean checkResult = false;

long crc = Long.parseLong(getString(R.string.crc));//获取字符资源中预埋的crc

ZipFile zf;

try{

String path = getApplicationContext().getPackageCodePath();//获取apk安装路径

zf = new ZipFile(path);//将apk封装成zip对象

ZipEntry ze = zf.getEntry("classes.dex");//获取apk中的classes.dex

long CurrentCRC = ze.getCrc();//计算当前应用classes.dex的crc

if(CurrentCRC != crc){//crc值对比

checkResult = true;

}

}catch(IOException e){

handleError();

checkResult = false;

}

return checkResult;

}

注意:一旦修改源代码,从新编译后classes.dex的CRC值就会变掉,所以正确的CRC值置不可以预置在代码中,能够考虑置放在资源文件中。

相关文章
相关标签/搜索