Android安全知识笔记合集

反编译

反编译代码

  • dex2jar 这个工具用于将dex文件转换成jar文件
  • jd-gui 这个工具用于将jar文件转换成java代码 ,使用jd-gui工具打开classes-dex2jar.jar这个文件就能查看Java代码

反编译资源

  • apktool 这个工具用于最大幅度地还原APK文件中的9-patch图片、布局、字符串等等一系列的资源。

没有反编译资源以前,AndroidManifest.xml和activity_main.xml这样的资源文件都是非明文的,没法阅读。php

从新打包

微信图片_20191207175045.png

smali文件夹的目录结构和咱们源码中src的目录结构是几乎同样的,主要的区别就是全部的java文件都变成了smali文件。smali文件其实也是真正的源代码,只不过它的语法和java彻底不一样,它有点相似于汇编的语法,是Android虚拟机所使用的寄存器语言html

使用smali语法,修改代码,就能从新编译本身的apk。可是apk还不能安全,由于还没签名。java

由于没法得到原来正版的签名,可使用Android Studio生成本身的签名,进行打包,生成本身的apk。android

参考:

blog.csdn.net/guolin_blog…web

混淆

混淆的好处:

  • 令 APK 难以被逆向工程,增长反编译的成本。
  • 打包时移除无用资源,减小 APK 体积。

启动混淆

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

复制代码
  • minifyEnabled 设置为 true 来开启混淆
  • 设置 shrinkResourcestrue 来开启资源的压缩。
  • 通常在打 release 包时才启用混淆,由于混淆会增长额外的编译时间,因此不建议在 debug 模式下启用。
  • 须要注意的是:只有在启用混淆的前提下开启资源压缩才会有效!
  • 以上代码中的 proguard-android.txt 表示 Android 系统为咱们提供的默认混淆规则文件,而 proguard-rules.pro 则是咱们想要自定义的混淆规则,

不能被混淆的元素

枚举

枚举类内部存在 values 方法,混淆后该方法会被从新命名,并抛出 NoSuchMethodException。Android 系统默认的混淆规则中已经添加了对于枚举类的处理,咱们无需再去作额外工做。算法

被反射的元素

缘由在于:代码混淆过程当中,被反射使用的元素会被重命名,然而反射依旧是按照先前的名称去寻找元素,因此会常常发生 NoSuchMethodExceptionNoSuchFiledException 问题。数据库

实体类

实体类即咱们常说的"数据类",固然常常伴随着序列化反序列化操做。不少人也应该都想到了,混淆是将本来有特定含义的"元素"转变为无心义的名称,因此,通过混淆的"洗礼"以后,序列化以后的 value 对应的 key 已然变为没有意义的字段,这确定是咱们不但愿的。api

反序列化的过程建立对象从根本上来讲仍是借助于反射,混淆以后 key 会被改变,因此也会违背咱们预期的效果。安全

四大组件

Android 中的四大组件一样不该该被混淆。缘由在于:bash

  1. 四大组件使用前都须要在 AndroidManifest.xml 文件中进行注册声明,然而混淆处理以后,四大组件的类名就会被篡改,实际使用的类与 manifest 中注册的类并不匹配,故而出错。
  2. 其余应用程序访问组件时可能会用到类的包名加类名,若是通过混淆,可能会没法找到对应组件或者产生异常。

JNI 调用的Java 方法

当 JNI 调用的 Java 方法被混淆后,方法名会变成无心义的名称,这就与 C++ 中本来的 Java 方法名不匹配,于是会没法找到所调用的方法。

其余不该该被混淆的

  • 自定义控件不须要被混淆
  • JavaScript 调用 Java 的方法不该混淆
  • Java 的 native 方法不该该被混淆
  • 项目中引用的第三方库也不建议混淆

参考

郭霖:blog.csdn.net/guolin_blog…

juejin.im/post/5d1717…

WebView

问题:WebView明文存储密码带来的安全漏洞
  • WebView组件默认开启了密码保存功能,会提示用户是否保存密码,当用户选择保存在WebView中输入的用户名和密码,则会被明文保存到应用数据目录的databases/webview.db中。攻击者可能经过root的方式访问该应用的WebView数据库,从而窃取本地明文存储的用户名和密码。
解决方案:
  • 开发者调用 WebView.getSettings().setSavePassword(false),显示调用API设置为false,让WebView不存储密码

四大组件

问题:动态注册Receiver风险
  • 使用BroadcastReceiver组件须要动态注册或者静态注册,若是动态注册广播,即在代码中使用registerReceiver()方法注册BroadcastReceiver,只有当registerReceiver()的代码执行到了才进行注册,取消时则调用unregisterReceiver()方法。但registerReceiver()方法注册的BroadcastReceiver是全局的而且默承认导出的,若是没有限制访问权限,能够被任意外部APP访问,向其传递Intent来执行特定的功能。所以,动态注册的BroadcastReceive可能会致使拒绝服务攻击、APP数据泄漏或是越权调用等安全风险
解决方案:
  • 1:在 AndroidManifest.xml 文件中使用静态注册 BroadcastReceiver,同时设置 exported="false",不被外部应用调用。 2:必须动态注册 BroadcastReceiver时,使用registerReceiver(BroadcastReceiver,IntentFilter,broadcastPermission,android.os.Handle)函数注册。 3:Android8.0新特性想要支持静态广播、须要添加intent.setComponent(new ComponentName()),详情能够自行查阅
问题:公共组件配置风险
  • Activity、Service、Provider、Receiver四大组件若配置为android:exported =”true”,将能够被外部应用调用,这样存在安全隐患的风险。
解决方案:
  • 在应用的AndroidManifest.xml文件中,设置组件的android:exported 属性为false或者经过设置自定义权限来限制对这些组件的访问。值得一提的是,若部分功能使用前提是配置必须使用exported为true,这种状况开发者应该根据实际状况来进行集成
问题:数据越权备份风险
  • Android 2.1以上的系统能够为APP提供应用程序数据的备份和恢复功能,该功能由AndroidMainfest.xml文件中的allowBackup 属性值控制,其默认值为true。当该属性没有显式设置为false时,攻击者可经过adb backupadb restore对APP的应用数据进行备份和恢复,从而可能获取明文存储的用户敏感信息,如用户的密码、证件号、手机号、交易密码、身份令牌、服务器通讯记录等。利用此类信息攻击者可伪造用户身份,盗取用户帐户资产,或者直接对服务器发起攻击。
解决方案:
  • 将AndroidMainfest.xml文件中的allowBackup属性值设置为false来关闭应用程序的备份和恢复功能;也可使用专业安全加固方案的本地数据保护功能,避免本地数据泄露。

数据存储安全:加密和JNI写入Native层

一、秘钥及敏感信息

此类配置应当妥善存放,不要在类中硬编码敏感信息,可使用JNI将敏感信息写到Native层

二、SharePreferences

首先不该当使用SharePreferences来存放敏感信息,sharedpreferces存储的xml文件数据可能被反编译拿到。存储一些配置信息时也要配置好访问权限,如私有的访问权限 MODE_PRIVATE(Activity.MODE_PRIVATE,//默认操做模式,表明该文件是私有数据,只能被应用自己访问,在该模式下,写入的内容会覆盖原文件的内容),避免配置信息被篡改。

三、SQLite数据库文件的安全性 – 描述:敏感信息是否明文存储 – 检测:检测数据库里面的重要信息,好比帐号密码之类的是否明文存储 – 建议:重要信息进行加密存储

日志数据泄露:Log控制,正式环境不打印

问题:日志数据泄露风险

  • 调试信息函数可能输出重要的调试信息,常见的就是Log日志类其中包含的信息可能会致使用户信息泄露,泄露核心代码逻辑等,为发起攻击提供便利,例如:Activity的组件名;通讯交互的日志;跟踪的变量值等
解决方案:
  • 应用内使用统一的Log控制基类,能够灵活的控制Log的输出打印。(测试环境容许打印日志、正式环境不打印);或者使用第三方的日志框架

参考:

www.jianshu.com/p/79b30238b…

zhuanlan.zhihu.com/p/35100057

网络安全:HTTPS、使用签名和数据加密加密

1.1 无处不在的安全隐患

  • 由于http协议是明文传输的,能够采起MD5值传输和存储,近几年MD5破解能力提升,因此如今一般生成MD5值时都须要加盐,例如MD5(name+pwd)做为密码存储,一样的密码生成的值是不同的,在必定程度上提升了安全性。
  • 攻击不必定须要用户名密码,或许能够直接打token和uid的主意。,一旦用户登陆后,服务器就经过token来标识身份。若是这个token被黑客劫持了,他就能够冒充你的身份进行攻击,若是token机制设计不合理,攻击者甚至能够直接暴力去撞token。大部分网站的机制也相似,服务器经过一个sessionId标识用户,攻击者一旦拿到这个sessionId,就能够去冒充一个合法用户。

1.2 使用https是否就万事大吉

  • https分单向认证和双向认证,大部分的应用场景是c/s模式,这时一般都是采用的单向认证的方式,也就是说能够保证客户端拿到的数据是后台发送的,攻击难度很大,除非你能忽悠别人安装并信任你的证书
  • 可是,不少人蹭wifi时或者在网上下载一些资源,系统提示要信任什么东西,看都不看就点肯定。
  • 使用抓包工具时,给目标设备安装并信任装包工具的自签名证书,这时候就能够分析https请求
    • 杜绝 HTTPS 抓包的原理很简单,其实就是拦截非法的证书,只经过咱们信任的 HTTPS 证书的请求。
    • 还有一种比较简单,直接设置okhttp禁用代理模式,也能够避免一些抓包。可是用户可能须要代理上网,这么禁止会引来其余问题
    • 参考:www.jianshu.com/p/11577eb0c…

1.3 使用签名和加密数据

上面能够看到,https并不能阻挡攻击者分析请求接口并发起恶意请求攻击,为了增长攻击者分析请求的难度,一般能够采用两种方式:

  • 使用签名。

    • 即给你的请求参数添加一个签名,后台服务接收到请求时,先验证签名,签名不正确的话,则不予处理。签名规则五花八门,大体策略就是根据请求参数作一些运算最后生成一个惟一的字符串当作sign
    • 微信支付的签名的规则能够参考:pay.weixin.qq.com/wiki/doc/ap…
  • 数据加密。

    • post到服务器和从服务器返回的数据都作加密,这样的话即便攻击者拿到你的数据,他不知道你的加密算法就无能为力了。
  • 秘钥使用JNI将敏感信息写到Native层

参考:

www.jianshu.com/p/fe0206f8b…

JNI:储存敏感信息,核心算法和秘钥

  • 一些常量是不会/不能被混淆的,这种敏感信息就须要额外保护
  • 核心算法和秘钥,通常选择放到native层

native代码的安全性保证

  • 相对于java代码容易被反编译,使用NDK开发出来的原生C++代码编译后生成的so库是一个二进制文件,这无疑增长了破解的难度。利用这个特性,能够将客户端敏感信息写在C++代码中,加强应用的安全性。
  • 万一别人将你的so库直接copy出来拿去用了呢?所以,咱们还须要在native层对应用的包名、签名进行鉴权校验,若是不是本身的应用,不返回相关信息,或者直接退出应用!

安全风险

  • 用ndk开发,将密钥放在so文件,加密解密操做都在so文件里,这从必定程度上提升了的安全性,挡住了一些逆向者,可是有经验的逆向者仍是会使用IDA破解的。
  • 在so文件中不存储密钥,so文件中对密钥进行加解密操做,将密钥加密后的密钥命名为其余普通文件,存放在assets目录下或者其余目录下,接着在so文件里面添加无关代码(花指令),虽然能够增长静态分析难度,可是可使用动态调式的方法,追踪加密解密函数,也能够查找到密钥内容。

参考:

www.jianshu.com/p/fe0206f8b…

zhuanlan.zhihu.com/p/34902225

即时通信安全篇(四):实例分析Android中密钥硬编码的风险

加壳与脱壳

不管是编译java代码生成的dex文件,仍是编译C/C++代码生成的so文件,反编译成本都不是特别的高。

加壳直观理解就是给程序加一层壳,能够用来对原程序进行资源压缩、防调试、防注入、防反编译,也就是说经过一个壳把原来的程序保护了起来。

咱们知道一个常规Android程序它的全部代码都在dex文件中,程序启动时要先把这个dex文件载入到内存中,因此若是要加壳的话,主要工做就是把原dex文件加密或者隐藏起来,放一个新的壳dex到apk中,程序启动时运行这个壳dex,而后这个壳dex在运行时再加载原dex,用一张图表示以下:

微信图片_20191207174907.png
  • xposed框架这样的hook技术,相似于降维打击,能够绕过加固技术轻松获取到dex文件。目前的乐固、360等大厂加固均可以绕过。

    • 加固也避免dex文件直接暴露在apk压缩文件中,可是加固也有明确的缺点,可能会影响启动的速度,apk体积增大,没法使用补丁,依然能够脱壳逆向。因此加固已经再也不被推荐使用,基本上大公司的apk都不会使用加固技术。

补充:hook和xposed

什么是 Hook

Hook 又叫“钩子”,它能够在事件传送的过程当中截获并监控事件的传输,将自身的代码与系统方法进行融入。这样当这些方法被调用时,也就能够执行咱们本身的代码。

Xposed

  • 能够在不修改APK的状况下影响程序运行(修改系统)的框架服务。
  • 替换本身的代码,使得程序加载Xposed的jar包,完成劫持
  • install的时候须要root权限,可是运行时不须要root权限

经过替换 /system/bin/app_process 程序控制 Zygote 进程,使得 app_process 在启动过程当中会加载 XposedBridge.jar 这个 Jar 包,从而完成对 Zygote 进程及其建立的 Dalvik 虚拟机的劫持。 Xposed 在开机的时候完成对全部的 Hook Function 的劫持,在原 Function 执行的先后加上自定义代码

Xposed框架介绍以及原理

XposedGithubrovo89大佬设计的一个针对Android平台的动态劫持项目,经过替换/system/bin/app_process程序控制Zygote进程,使得app_process在启动过程当中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其建立的Dalvik虚拟机的劫持。

由于Xposed工做原理是在/system/bin目录下替换文件,在install的时候须要root权限,可是运行时不须要root权限。

看到这里不少人会很懵,什么是Zygote?简单来讲在Android系统中,应用程序进程都是由Zygote进程孵化出来的,而Zygote进程是由Init进程启动的。Zygote进程在启动时会建立一个Dalvik虚拟机实例,每当它孵化一个新的应用程序进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面去,而一个应用程序进程被Zygote进程孵化出来的时候,不只会得到Zygote进程中的Dalvik虚拟机实例拷贝,还会与Zygote一块儿共享Java运行时库。这也就是能够将XposedBridge这个jar包加载到每个Android应用程序中的缘由。XposedBridge有一个私有的Native(JNI)方法hookMethodNative,这个方法也在app_process中使用。这个函数提供一个方法对象利用JavaReflection机制来对内置方法覆写。。。。等等这些都会借鉴各路大神的思路和分析,总而言之,就是从底层替换方法,可让咱们在不修改APK源码的状况下,经过本身编写的模块来影响程序运行的框架服务,实现相似于自动抢红包、微信消息自动回复等功能。 其实,从本质上来说,Xposed模块也是一个Android程序。但与普通程序不一样的是,想要让写出的Android程序成为一个``Xposed 模块,要额外多完成如下四个硬性任务:

一、让手机上的xposed框架知道咱们安装的这个程序是个xposed模块。

二、模块里要包含有xposed的API的jar包,以实现下一步的hook操做。

三、这个模块里面要有对目标程序进行hook操做的方法。

四、要让手机上的xposed框架知道,咱们编写的xposed模块中,哪个方法是实现hook操做的。
复制代码

参考:

www.jianshu.com/p/fe0206f8b…

加密算法

加密主要有对称加密、非对称加密,不可逆加密。

对称加密AES

AES主要是用在数据自己的加密,即便传输过程当中被截取了,也是加密事后的数据。但AES的弊端的是,客户端加密的话,密钥确定是储存在app中,若是app被成功破解了,数据也就被暴露了。因此只有app自己程序的安全也解决了,app才能相对安全。

非对称加密RSA

由于RSA加密有个长度限制,这就致使了RSA加密不能用于全部的数据交互。可是能够用到一些短数据,好比用户我的信息之类的,在交易中,一次订单的数据也不是很大等。

不可逆加密

好比MD5加密SHA加密等。所谓的不可逆加密就是,只能单向加密,不能反向解密。MD5把数据加密,最后获得固定长度的16进制编码。这个加密的做用通常是匹配验证,验证某个数据是否改变。好比密码,在向服务器存储密码,通常不会存储明文密码。安卓本地存储个标志也通常不会明文存储。

Android官方

推出了JetPack Security 。

确保数据安全 - 深刻解读加密与安全开发 | AndroidDevSummit 中文字幕视频

相关文章
相关标签/搜索