移动APP安全测试总结.docx
《移动APP安全测试总结.docx》由会员分享,可在线阅读,更多相关《移动APP安全测试总结.docx(31页珍藏版)》请在冰豆网上搜索。
移动APP安全测试总结
1、移动APP安全风险分析
1.1、安全威胁分析
安全威胁从三个不同环节进行划分,主要分为客户端威胁、数据传输端威胁和服务端的威胁。
1.2、面临的主要风险
1.3、Android测试思维导图
1.4 、反编译工具
有两种反编译方式,dex2jar和apktool,两个工具反编译的效果是不一样的,dex2jar反编译出java源代码,apktool反编译出来的是java汇编代码。
dex2jar主要是用来把之前zip解压出来的classed.dex转成jar包的
jd-gui主要是用来打开Jar包的
2、本地客户端安全
2.1、反编译保护
2.1.1、问题描述
APP源代码对于一个公司是非常重要的信息资源,对APP的保护也尤为重要,APP的反编译会造成源代码被恶意者读取,以及APP的逻辑设计,
反编译方法
我们一般想要反编译一个apk,无非就是想获得三样东西:
图片资源、XML资源、代码资源
一. 图片资源获取
首先准备一个apk,这里是一个.apk后缀的文件,我们先把后缀改成,zip,打开zip文件在res目录下,我们就可以获取到我们需要的图片了。
二. XML资源获取
我们可以在刚刚打开的zip文件目录下看到很多.xml的文件,这个xml文件是无法直接打开的,当你尝试着打开的时候都是乱码或者是空白,那么我们要如何获取到这个xml资源呢,这时候就需要借助一个jar包,就是它,axmlprinter2.jar,这个东西你只要XX下,就能搜到。
然后你把他放跟你解压出来的xml放在同级目录下,用cmd命令找到这个目录,
我这边的示例是将xml放在了E盘,大家根据情况,cd到自己解压出来的目录下,然后执行
java -jarAXMLPrinter2.jarxxxxx.xml>xxxxx.txt
这个时候你就能获取到xml里的东西啦
三. 代码资源获取
这个重中之重了,这也是我们主要想要获取到的东西。
但是存在一点,这里能够正确反编译出来的只有未加密或者没有混淆的代码,如果想要反编译一些加密或者混淆后代码,俺们就需要其他途径解决了
首先要准备两样东西:
dex2jar.rar和jd-gui.zip这两个工具。
dex2jar主要是用来把之前zip解压出来的classed.dex转成jar包的
jd-gui主要是用来打开Jar包的
dex2jar用法:
把dex2jar解压后,然后将之前zip的classes.dex放到dex2jar目录下,
注意,必须要跟dex2jar.bat是同级目录。
然后又要用到cmd,cd到dex2jar目录下,打命令行
dex2jar.bat classes.dex
然后你的目录里会多一个jar包
多了一个classes-dex2jar.jar的文件
然后在用jd-gui把jar包打开,最终apk的代码就这样被剥离出来了
2.1.2 、检测方法
通过反编译工具看是否能够对APP进行反编译
2.1.3、修复方法
采用加密和混淆技术达到反编译保护。
混淆技术作用是增加了用户反编译后阅读代码的难度。
2.2、APP二次打包
2.2.1 二次打包描述
“AndroidAPP二次打包”则是盗版正规AndroidAPP,破解后植入恶意代码重新打包。
不管从性能、用户体验、外观它都跟正规APP一模一样但是背后它确悄悄运行着可怕的程序,它会在不知不觉中浪费手机电量、流量,恶意扣费、偷窥隐私等等行为。
面对二次打包不少公司都有自己的防范措施,知名公司的APP几乎都是自己在程序内部做过处理防止其APP被二次打包,一旦打包后重新运行则程序自动退出。
接下来,我就来详解一下如何防止APP被二次打包。
要实现代码内部防止APP被二次打包首先得了解APK的机器识别原理,APK的唯一识别是依靠包名和签名来做鉴定的,类似豌豆夹的洗白白、360手机卫士等安全软件对APK的山寨识别,他们就是依赖包名来确定APK然后通过签名来确定其是否山寨。
所以说自己的程序内部在启动的时候可以通过获取APK本身的签名然后和正确的签名做对比来识别自己是否被二次打包。
2.2.2 防二次打包检测方法
利用二次打包工具对APP进行二次打包,看APP能否成功打包运行,如果重新打包后无法运行程序说明有防二次打包安全措施。
2.2.3 防二次打包修复方法
采用签名的方法进行保护:
获取二次打包后APK的签名与正确的APK签名做对比,判断APK程序是否进行过二次打包。
建议:
客户端使用从属方证书进行签名后进行发布而不是使用第三方开发商的证书进行签名,以防开发商内部监管异常,证书滥用的情况出现。
2.3、组件导出安全
2.3.1、四大组件描述
Android主要包含4大组件,分别是activity组件、service组件、contentprovider组件和broadcastreceiver组件。
Activity组件
(1)一个Activity通常就是一个单独的屏幕(窗口)。
(2)Activity之间通过Intent进行通信。
(3)android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity。
Service组件
(1)service用于在后台完成用户指定的操作。
(2)开发人员需要在应用程序AndroidManifest.xml配置文件中声明全部的service,使用标签。
(3)Service通常位于后台运行,它一般不需要与用户交互,因此Service组件没有图形用户界面。
Service组件需要继承Service基类。
Service组件通常用于为其他组件提供后台服务或监控其他组件的运行状态。
Content Provider组件
(1)android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。
其他应用可以通过ContentResolver类从该内容提供者中获取或存入数据。
(2)只有需要在多个应用程序间共享数据是才需要内容提供者。
例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。
它的好处是统一数据访问方式。
(3)ContentProvider实现数据共享。
ContentProvider用于保存和获取数据,并使其对所有应用程序可见。
这是不同应用程序间共享数据的唯一方式,因为android没有提供所有应用共同访问的公共存储区。
broadcast receiver
(1)你的应用可以使用它对外部事件进行过滤,只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。
广播接收器没有用户界面。
然而,它们可以启动一个activity或serice来响应它们收到的信息,或者用NotificationManager来通知用户。
通知可以用很多种方式来吸引用户的注意力,例如闪动背灯、震动、播放声音等。
一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
(2)广播接收者的注册有两种方法,分别是程序动态注册和AndroidManifest文件中进行静态注册。
(3)动态注册广播接收器特点是当用来注册的Activity关掉后,广播也就失效了。
静态注册无需担忧广播接收器是否被关闭,只要设备是开启状态,广播接收器也是打开着的。
也就是说哪怕app本身未启动,该app订阅的广播在触发时也会对它起作用。
四大组件总结
(1)4大组件的注册
4大基本组件都需要注册才能使用,每个Activity、service、ContentProvider都需要在AndroidManifest文件中进行配置。
AndroidManifest文件中未进行声明的activity、服务以及内容提供者将不为系统所见,从而也就不可用。
而broadcast receiver广播接收者的注册分静态注册(在AndroidManifest文件中进行配置)和通过代码动态创建并以调用Context.registerReceiver()的方式注册至系统。
需要注意的是在AndroidManifest文件中进行配置的广播接收者会随系统的启动而一直处于活跃状态,只要接收到感兴趣的广播就会触发(即使程序未运行)。
(2)4大组件的激活
内容提供者的激活:
当接收到ContentResolver发出的请求后,内容提供者被激活。
而其它三种组件activity、服务和广播接收器被一种叫做intent的异步消息所激活。
2.3.2、组件安全检查方法
1、 AndroidManifest.xml文件中activity组件里面有设置android:
exported为true,表示此组件可以被外部应用调用。
2、 AndroidManifest.xml文件中activity组件里面有设置android:
exported为false,表示此组件不可以被外部应用调用。
只有同一个应用的组件或者有着同样userID的应用可以
3、 AndroidManifest.xml文件中activity组件里面没有设置android:
exported属性,但是有intent-filter,则exported默认属性为true,true表示此组件可以被外部应用调用。
4、 AndroidManifest.xml文件中activity组件里面没有设置android:
exported属性,也没有设置intent-filter,则exported默认属性为false,false表示此组件不可以被外部应用调用。
只有同一个应用的组件或者有着同样userID的应用可以
备注:
采用drozer工具可以进行检测组件是否存在导出风险
2.3.3、修复建议
(1)如果应用的Service组件不必要导出,或者组件配置了intent filter标签,建议显示设置组件的“android:
exported”属性为false
(2)如果组件必须要提供给外部应用使用,建议对组件进行权限控制
2.4、Webview漏洞
2.4.1、WebView任意代码执行漏洞
2.4.1.1、 描述
出现该漏洞的原因有三个
WebView 中addJavascriptInterface()接口
WebView 内置导出的searchBoxJavaBridge_对象
WebView 内置导出的accessibility和accessibilityTraversalObject 对象
addJavascriptInterface 接口引起远程代码执行漏洞
JS调用Android的其中一个方式是通过addJavascriptInterface接口进行对象映射,当JS拿到Android这个对象后,就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。
searchBoxJavaBridge_接口引起远程代码执行漏洞
在Android3.0以下,Android系统会默认通过searchBoxJavaBridge_的Js接口给WebView添加一个JS映射对象:
searchBoxJavaBridge_对象
该接口可能被利用,实现远程任意代码。
accessibility和accessibilityTraversal接口引起远程代码执行漏洞
问题类似以上
2.4.1.2 、检测方法
addJavascriptInterface 接口引起远程代码执行漏洞
检查是通过addJavascriptInterface接口进行对象映射
searchBoxJavaBridge_接口引起远程代码执行漏洞
检查是否通过searchBoxJavaBridge_的Js接口给WebView添加一个JS映射对象
accessibility和accessibilityTraversal接口引起远程代码执行漏洞
问题类似以上
2.4.1.3、 修复建议
addJavascriptInterface 接口引起远程代码执行漏洞
B1. Android4.2版本之后
Google 在Android4.2版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞×××
B2. Android4.2版本之前
在Android4.2版本之前采用拦截prompt()进行漏洞修复。
searchBoxJavaBridge_接口引起远程代码执行漏洞
删除searchBoxJavaBridge_接口
// 通过调用该方法删除接口
removeJavascriptInterface();
accessibility和accessibilityTraversal接口引起远程代码执行漏洞
删除accessibility和accessibilityTraversal接口
2.4.2、密码明文存储漏洞
2.4.2.1、描述
WebView默认开启密码保存功能:
mWebView.setSavePassword(true)
开启后,在用户输入密码时,会弹出提示框:
询问用户是否保存密码;
如果选择”是”,密码会被明文保到/data/data/com.package.name/databases/webview.db 中,这样就有被盗取密码的危险
2.4.2.2 、检测方法
方法1、用户输入密码时看是否有弹出提示框,询问用户是否保存密码,如果有询问则表示存在漏洞,否则不存在。
方法2、检查代码中setSavePassword的值是否为false。
2.4.2.3 、修复建议
关闭密码保存提醒
WebSettings.setSavePassword(false)
2.5、数据安全-本地敏感信息安全
2.5.1、APP所在目录的文件权限
2.5.1.1、 问题描述
测试客户端APP所在目录的文件权限是否设置正确,非root账户是否可以读,写,执行APP目录下的文件。
2.5.1.2 检测方法
采用ls–l查看app目录的文件权限,其它组成员不允许读写权限。
Linux文件权限为第一个为文件所有者对此文件的权限,第二个为所有者所在组的其它成员对此文件的权限,第三个为其他组成员对此文件的权限。
2.5.1.3 修复建议
检查App所在的目录,其权限必须为不允许其他组成员读写
2.5.2、SQLite数据库文件的安全性
2.5.2.1、 描述
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统.是开源的,高效率的,可嵌入且程序驱动的数据库。
我们都知道,Android系统内置了SQLite数据库,并且提供了一整套的API用于对数据库进行增删改查操作。
数据库存储是我们经常会使用到的一种存储方式,相信大多数朋友对它的使用方法都已经比较熟悉了吧。
在Android中,我们既可以使用原生的SQL语句来对数据进行操作,也可以使用AndroidAPI提供的CRUD方法来对数据库进行操作,两种方式各有特点,选择使用哪一种就全凭个人喜好了。
不过,使用SQLite来存储数据却存在着一个问题。
因为大多数的Android手机都是Root过的,而Root过的手机都可以进入到/data/data//databases目录下面,在这里就可以查看到数据库中存储的所有数据。
如果是一般的数据还好,但是当涉及到一些账号密码,或者聊天内容的时候,我们的程序就会面临严重的安全漏洞隐患。
2.5.2.2、 检测方法
手机进行root之后,查看/data/data//databases下的数据库文件是否包含敏感信息。
2.5.2.3 、修复建议
重要信息进行加密存储
2.5.3、Logcat日志
2.5.3.1、描述
检测客户端对应的Logcat日志是否会打印一些用户或服务器的敏感信息。
2.5.3.2、检测方法
通过usb连接手机,然后使用adblogcat-vtime>d:
\xx的方式获取logcat信息
或者使用DDMS工具查看logcat信息。
2.5.3.3、修复建议
具有敏感信息的调试信息开关一定要关闭。
对于安卓开发来讲,我们解决敏感信息问题就是对重要数据进行加密存储,log日志不打印敏感信息。
切记不要把账号密码等敏感信息保存在本地明文存储,如果一定要存储敏感信息务必进行加密存储重要信息。
2.5.4、敏感数据明文存储于Sdcard
2.5.4.1、描述
Android提供了几种保存持久化应用数据的选择,其中之一就是外部存储(/sdcard,/mnt/sdcard)。
外部存储包括设备内部的微型或标准大小的SD卡,挂载到PC上的Android设备存储卡以及Android/obb目录。
Android4.1之前的版本,存放在外部存储的文件是world-readable(能够被任何用户读取的)和world-writable(能够被任何用户写入)。
从Android4.1到Android4.3,一个app想要写入外部存储的任意文件时,只需在AndroidManifest文件中声明WRITE_EXTERNAL_STORAGE权限。
但从Android4.4开始,引入了基于目录结构创建分组和文件模式,这使得一个app在外部存储中的只能在以自己包名命名的目录下才具有文件的读写权限。
非系统级的app只允许在Android/data//目录下操作。
因此,每个app的文件读写权限被独立开来,不能互相访问。
上面描述的访问权限限制的不足,导致写入到外部存储的文件可能存在被同一设备上不同的app修改和读取的风险(Android4.4之前版本)。
2.5.4.2、检测方法
查看是否有代码把内容写入到外部存储设备。
2.5.4.3、修复建议
在将文件保存到外部存储之前,先对文件内容进行加密。
2.6、键盘安全风险
2.6.1、键盘劫持测试
2.6.1.1、描述
安卓应用中的输入框默认使用系统软键盘,手机安装×××后,×××可以通过替换系统软键盘,记录应用的密码。
2.6.1.2、检测方法
通过观察app在输入密码的地方是否会弹出自定义的软键盘。
2.6.1.3、修复建议
建议客户端开发自定义软键盘而不是使用系统软件盘以防止键盘劫持×××。
2.6.2、软键盘安全性测试
2.6.2.1、 描述
测试客户端是否使用随机布局的密码软键盘。
2.6.2.2、检测方法
用眼观察每次弹出来的自定义的软键盘是否随机变化布局
2.6.2.3、修复建议
建议客户端对自定义软键盘进行随机化处理,同时在每次点击输入框时都进行随机初始化。
2.7、屏幕录像测试
2.7.1、描述
测试通过连续截图,是否可以捕捉到用户密码输入框的密码。
2.7.2、检测方法
通过连续截图,是否可以捕捉到用户密码输入框的密码。
2.7.3 、修复建议
建议客户端针对第三方或系统截屏编写抵抗逻辑,例如屏蔽和截屏相关的函数或是当客户端处于进程栈顶层时将截屏图片用纯黑×××片对象进行覆盖。
2.8、界面劫持保护
2.8.1、界面劫描述
Activity劫持是指当启动某个窗口组件时,被恶意应用探知,若该窗口界面是恶意程序预设的×××对象,恶意应用将启动自己仿冒的界面覆盖原界面,用户在毫无察觉的情况下输入登录信息,恶意程序在把获取的数据返回给服务端。
需要理解,Android启动一个Activity时,是这样设计的,给Activity加入一个标志位FLAG_ACTIVITY_NEW_TASK,就能使它置于栈顶并立马呈现给用户。
但是这样的设计却有一个缺陷。
如果这个Activity是用于盗号的伪装Activity呢?
这种现象在XcodeGhost事件中,已经被证实是可以实现的。
在Android系统当中,程序可以枚举当前运行的进程而不需要声明其他权限,这样的话,就可以编写一个程序,启动一个后台的服务,这个服务不断地扫描当前运行的进程,当发现目标进程启动时,就启动一个伪装的Activity。
如果这个Activity是登录界面,那么就可以从中获取用户的账号密码,具体的过程如下图:
2.8.2、界面劫持防护方法
作为一名移动应用开发者,要防御APP被界面劫持,最简单的方法是在登录窗口等关键Activity的onPause方法中检测最前端Activity应用是不是自身或者是系统应用。
如果检测到不是自己,则弹出告警或者退出。
2.8.3、界面劫持案例
应用存在钓鱼劫持风险。
应用程序没有做防钓鱼劫持措施,通过劫持应用程序的登录界面,可以获取用户的账号和密码,可能导致用户账号信息的泄露。
2.8.4、整改建议
应用程序自身通过获取栈顶activity,判断系统当前运行的程序,一旦发现应用切换(可能被劫持),给予用户提示以防范钓鱼程序的欺诈。
获取栈顶activity(如下图),当涉及敏感activity(登录、交易等)切换时,判断当前是否仍留在原程序,若不是则通过Toast给予用户提示。
使用HTML5架构或android+HTML5混合开发,实现登陆、支付等关键页面,降低被劫持的风险。
2.9、本地拒绝服务
2.9.1、漏洞描述
Android系统提供了Activity、Service和BroadcastReceiver等组件,并提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android系统则根据此Intent的描述,负责找到对应的组件,将Intent传递给调用的组件,并完成组件的调用[1]。
Android应用本地拒绝服务漏洞源于程序没有对Intent.getXXXExtra()获取的异常或者畸形数据处理时没有进行异常捕获,从而导致×××者可通过向受害者应用发送此类空数据、异常或者畸形数据来达到使该应用crash的目的,简单的说就是×××者通过intent发送空数据、异常或畸形数据给受害者应用,导致其崩溃。
本地拒绝服务漏洞影响范围:
Android系统所有版本
2.9.2、漏洞检测方法
使用Android扫描工具可以进行扫描。
2.9.3、 修复建议
本地拒绝服务漏洞修复建议:
1)将不必要的导出的组件设置为不导出
出于安全考虑,应将不必要的组件导出,防止引起拒绝服务,尤其是杀毒、安全防护、锁屏防盗等安全应用;在AndroidMenifest.xml文件中,将相应组件的“android:
exported”属性设置为“false”,如下示例:
exported="false">
2)intent处理数据时进行捕获异常
建议处理通过Intent.getXXXExtra()获取的数据时进行以下判断,以及用try catch方式进行捕获所有异常,以防止应用出现拒绝服务漏洞:
1)空指针异常;
2)类型转换异常;
3)数组越界访问异常;
4)类未定义异常;
5)其他异常;
2.10、数据备份allowBackup
2.10.1、漏洞描述
Android APILevel8 及其以上Android系统提供了为应用程序数据的备份和恢复功能,此功能的开关决定于该应用程序中 AndroidManifest.xml 文件中的a