大佬:“这个 APP 破解下,能够兼容客户已出货的产品”
我:“这个不合适吧”
大佬:“这个客户对咱们很重要”
我:“好吧”
而后,就是经过反编译某 APP ,分析蓝牙交互协议,在新的 APP 中去兼容已出货的设备,达到无缝对接。 –这种场景在开发中仍是比较常常碰到的。
随着移动互联网向社会生活的各个领域渗透,APP 的使用愈来愈普遍。但 Android 系统因为其开源的属性,市场上针对开源代码定制的 ROM 良莠不齐(特别中国区域),在系统层面的安全防范和易损性都不同,Android 应用市场对 APP 的审核相对 iOS 来讲也比较宽泛,市场上一些主流的 APP 虽然多少都作了一些安全防范,但因为大部分 APP 不涉及资金安全,因此对安全的重视程度不够;并且因为安全是门系统学科,绝大部分 APP 层的开发人员缺少对 APP 安全意识及措施,致使被有心者有隙可乘。android
Android 开发是当前最火的话题之一,但不多开发者会讨论这个领域的安全问题,除了专业从业者,但移动应用安全隐患也给发展带来了挑战。c++
声明,我不是专业的安全人员,从事的跟安全工做也没有什么关系,本文从自已平时涉及的项目出发,对客户端的代码质量、代码篡改、不安全的数据储存、不安全的通讯、不安全的认证、加密不足等安全问题做了说明,从普通开发者角度尽可能去提升自已的 APP 安全,以下降代码安全漏洞,减小代码被利用的可能性,避免信任危机、经济损失和法律风险。web
Android 病毒就是手机木马,主要是一些恶意的应用程序。手机木马有的独立存在,有的则假装成图片文件的方式附在正版 APP 上,隐蔽性极强,部分病毒还会出现变种,而且一代比一代更强大。算法
这些病毒有一些通用的特征:sql
虽然 Java 代码通常要作混淆,可是 Android 的几大组件的建立方式是依赖注入的方式,所以不能被混淆,并且目前经常使用的一些反编译工具好比 Apktool 等可以绝不费劲的还原 Java 里的明文信息,Native 里的库信息也能够经过 objdump 或 IDA 获取。所以一旦 Java 或 Native 代码里存在明文敏感信息,基本上是毫无安全而言的。数据库
即反编译后从新加入恶意的代码逻辑,重新打包一个 APK 文件。重打包的目的通常都是上面提到和病毒结合,对正版 APK 进行解包,插入恶意病毒后从新打包并发布,所以假装性很强。截住 APP 重打包就必定程度上防止了病毒的传播。跨域
通常经过进程注入或者调试进程的方式来 Hook 进程,改变程序运行的逻辑和顺序,获取程序运行的内存信息,也就是用户全部的行为都被监控起来,这也是盗取账号密码最经常使用的一种方式。数组
固然 Hook 行为不必定彻底是恶意的,好比有些安全软件会利用 Hook 的功能作主动防护。通常来讲,Hook 须要获取 root 权限或者跟被 Hook 进程相同的权限,所以若是你的手机没有被 root,并且是正版 APK 的话,被注入仍是很困难的。 浏览器
传输过程最多见的劫持就是中间人攻击。不少安全要求较高的应用程序要求全部的业务请求都是经过 Https,可是 Https 的中间人攻击也逐渐多了起来,并且在实际使用中,证书交换和验证在一些山寨手机或者非主流 ROM 上面存在一些问题,让 Https 的使用碰到阻碍。安全
支付密码通常是经过键盘输入的,键盘输入的安全直接影响了密码的安全。键盘的安全隐患来自三个方面:
因为如今 Hybrid APP 的盛行(混合开发),Webview 在 APP 的使用也是愈来愈多,Android 系统 Webview 存在一些漏洞,形成 js 提权。最为著名的就是传说中 js 注入漏洞和 webkit xss 漏洞。
PermissionGroup 能够对 permission 进行一个逻辑上的分组。若是 PermissionGroup 的属性为空,会致使权限定义无效,且其余 APP 没法使用该权限。
开发建议:设置 PermissionGroup 属性值或者不使用 PermissionGroup。
因为对 APP 的自定义 permission 的 protectionLevel 属性设置不当,会致使组件(如:content provider)数据泄露危险。最好的权限设置应为 signature 或signatureOrSystem ,进而避免被第三方应用利用。
开发建议:注意使用 signature 或 signatureOrSystem 防止其余 APP 注册或接受该 APP 的消息,提升安全性。
经过 sharedUserId,可让拥有同一个 User Id 的多个 APP 运行在同一个进程中,互相访问任意资源。将 sharedUserId 设置为 android.uid.system,能够把 APP 放到系统进程中,APP 将得到极大的权限。若是 APP 同时有 master key 漏洞,容易致使被 root。
开发建议:合理设置软件权限。
当这个标志被设置成 true 或不设置该标志位时,应用程序数据能够备份和恢复,adb 调试备份容许恶意攻击者复制应用程序数据。
开发建议:设置 AndroidManifest.xml 的 android:allowBackup 标志为 false。
在 AndroidManifest.xml 中定义 Debuggable 项,若是该项被打开,APP 存在被恶意程序调试的风险,可能致使泄露敏感信息等问题。
开发建议:显示的设置 AndroidManifest.xml 的 debuggable 标志为 false。
Activity、activity-alias、service、receiver 组件对外暴露会致使数据泄露和恶意的攻击。
开发建议:最小化组件暴露。对不会参与跨应用调用的组件添加 android:exported=false 属性。
设置组件访问权限。对跨应用间调用的组件或者公开的 receiver、service、activity 和 activity-alias 设置权限,同时将权限的 protectionLevel 设置为 signature 或 signatureOrSystem。组件传输数据验证。对组件之间,特别是跨应用的组件之间的数据传入与返回作验证和增长异常处理,防止恶意调试数据传入,更要防止敏感数据返回。
建立隐式 Intent 时,Android 系统经过将 Intent 的内容与在设备上其余应用的清单文件中声明的 Intent 过滤器进行比较,从而找到要启动的相应组件。若是 Intent 与 Intent 过滤器匹配,则系统将启动该组件,并将其传递给对象。若是多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。
为了确保应用的安全性,启动 Service 时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。使用隐式 Intent 启动服务存在安全隐患,由于您没法肯定哪些服务将响应 Intent,且用户没法看到哪些服务已启动。从 Android 5.0(API 级别 21)开始,若是使用隐式 Intent 调用 bindService(),系统会抛出异常。
开发建议:为了确保应用的安全性,启动 Service 时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。使用隐式 Intent 启动服务存在安全隐患,由于您没法肯定哪些服务将响应 Intent,且用户没法看到哪些服务已启动。从 Android 5.0(API 级别 21)开始,若是使用隐式 Intent 调用 bindService(),系统会抛出异常。
影响范围
所有。从 Android 5.0(API 级别 21)开始,若是使用隐式 Intent 调用 bindService(),系统会抛出异常。
Intent Scheme URI 是一种特殊的 URL 格式,用来经过 Web 页面启动已安装应用的 Activity 组件,大多数主流浏览器都支持此功能。
Android Browser 的攻击手段—— Intent Scheme URLs 攻击。这种攻击方式利用了浏览器保护措施的不足,经过浏览器做为桥梁间接实现 Intend-Based 攻击。相比于普通 Intend-Based 攻击,这种方式极具隐蔽性,
若是在 APP 中,没有检查获取到的 load_url 的值,攻击者能够构造钓鱼网站,诱导用户点击加载,就能够盗取用户信息。因此,对 Intent URI 的处理不当时,就会致使基于 Intent 的攻击。
若是浏览器支持 Intent Scheme URI 语法,通常会分三个步骤进行处理:
关键点
Intent.parseUri 函数,经过扫描出全部调用了 Intent.parseUri 方法的路径,并检测是否使用以下的策略。
比较安全的使用 Intent Scheme URI 方法是:
若是使用了 Intent.parseUri 函数,获取的 intent 必须严格过滤,intent 至少包含 addCategory(android.intent.category.BROWSABLE),setComponent(null),setSelector(null)3 个策略。
因此,在检的时候只要根据 Intent.parseUri 函数返回的 Intent 对象有没有按照如下方式实现便可作出判断:
// convert intent scheme URL to intent object Intent intent = Intent.parseUri(uri); // forbid launching activities without BROWSABLE category intent.addCategory(android.intent.category.BROWSABLE); // forbid explicit call intent.setComponent(null); // forbid intent with selector intent intent.setSelector(null); // start the activity by the intent context.startActivityIfNeeded(intent, -1)
开发建议:若是使用了 Intent.parseUri 函数,获取的 intent 必须严格过滤,intent 至少包含 addCategory(android.intent.category.BROWSABLE),setComponent(null),setSelector(null)3 个策略。除了以上作法,最佳处理不要信任任何来自网页端的任何 intent,为了安全起见,使用网页传过来的 intent 时,要进行过滤和检查。
Android 系统提供了 Activity、Service 和 Broadcast Receiver 等组件,并提供了 Intent 机制来协助应用间的交互与通信,Intent 负责对应用中一次操做的动做、动做涉及数据、附加数据进行描述,Android 系统则根据此 Intent 的描述,负责找到对应的组件,将 Intent 传递给调用的组件,并完成组件的调用。Android 应用本地拒绝服务漏洞源于程序没有对 Intent.GetXXXExtra() 获取的异常或者畸形数据处理时没有进行异常捕获,从而致使攻击者可经过向受害者应用发送此类空数据、异常或者畸形数据来达到使该应用 Crash 的目的,简单的说就是攻击者经过 Intent 发送空数据、异常或畸形数据给受害者应用,致使其崩溃。
对导出的组件传递一个不存在的序列化对象,若没有 try…catch 捕获异常就会崩溃
ComponentName cn = new ComponentName(com.test, com.test.TargetActivity) Intent i = new Intent() i.setComponentName(cn) i.putExtra(key, new CustomSeriable()) startActivity(i) public class DataSchema implements Serializable { public DataSchema() { super(); } }
NullPointerException 异常致使的拒绝服务
源于程序没有对 getAction() 等获取到的数据进行空指针判断,从而致使了空指针异常致使应用崩溃
风险代码:
Intent i = new Intent(); if (i.getAction().equals(TestForNullPointerException)) { Log.d(TAG, Test for Android Refuse Service Bug); }
ClassCastException 异常致使的拒绝服务
源于程序没有对 getSerializableExtra() 等获取到的数据进行类型判断而进行强制类型转换,从而致使类型转换异常致使拒绝服务漏洞
风险代码:
Intent i = getIntent(); String test = (String) i.getSerializableExtra(serializable\_key);
IndexOutOfBoundsException 异常致使拒绝服务漏洞
源于程序没有对 getIntegerArrayListExtra() 等获取到的数据数组元素大小判断,致使数组访问越界而形成拒绝服务漏洞
风险代码:
Intent intent = getIntent(); ArrayList<Integer> intArray = intent.getIntegerArrayListExtra(user\_id); if (intArray != null) { for (int i = 0; i < 10; i++) { intArray.get(i); } }
ClassNotFoundException 异常致使的拒绝服务漏洞
Intent i = getIntent(); getSerializableExtra(key);
开发建议:将比不要导出的组建设置为不导出
在处理 Intent 数据时,进行捕获异常,经过 getXXXExtra() 获取的数据时进行如下判断,以及用 try catch 方式捕获全部异常,防止出现拒绝服务漏洞,包括:空指针异常、类型转换异常、数组越界访问异常、类未定义异常、其余异常
Try{ .... xxx.getXXXExtra() .... }Catch Exception{ ** ** **// 为空便可** }
一些 APP 在正式发布前,为了方便调试 APP,都会在 APP 里集成一些调试或测试界面。这些测试界面可能包含敏感的信息。
从 Android APP 的结构来讲,dex 文件是最重要、最须要保护的,由于 dex 中存放了代码的信息,开发者经过使用 dex2jar 和 jd-gui 简单几步就能够查看到源码。
Andriod 应用程序使用 Java 开发,可经过反编译的方式获取对应的源码
ProGuard 是一个免费的 Java 类文件的压缩,优化,混肴器
新建个 Android 工程以后,proguard.cfg 文件会在工程的根目录下自动建立文件定义了混淆器是怎样优化和混淆你的代码
目前开发经常使用方法:
SQLite 作为 android 平台的数据库,对于数据库查询,若是开发者采用字符串连接方式构造 SQL 语句,就会产生 SQL 注入。
开发建议:
APP 在使用 openOrCreateDatabase 建立数据库时,将数据库设置了全局的可读权限,攻击者恶意读取数据库内容,获取敏感信息。在设置数据库属性时若是设置全局可写,攻击者可能会篡改、伪造内容,能够能会进行诈骗等行为,形成用户财产损失。
开发建议
因为 Android 剪贴板的内容向任何权限的 APP 开放,很容易就被嗅探泄密。同一部手机中安装的其余 APP,甚至是一些权限不高的 APP,均可以经过剪贴板功能获取剪贴板中的敏感信息。
风险代码:
clipBtn = (Button) findViewById(R.id.btn\_clip); clipBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD\_SERVICE); ClipData clip1 = ClipData.newPlainText(label,password=123456); clipboard.setPrimaryClip(clip1); } });
开发建议:避免使用剪贴板敏文存储敏感信息或进行加密
在代码中禁止硬编码私钥等敏感信息,攻击者反编译代码,便可拿到。
APP 建立 Intent 传递数据到其余 Activity,若是建立的 Activity 不是在同一个 Task 中打开,就极可能被其余的 Activity 劫持读取到 Intent 内容,跨 Task 的Activity 经过 Intent 传递敏感信息是不安全的。
开发建议:尽可能避免使用包含 FLAG_ACTIVITY_NEW_TASK 标志的 Intent 来传递敏感信息。
使用 pendingIntent 时候,若是使用了一个空 Intent,会致使恶意用户劫持 Intent 的内容。禁止使用空 intent 去构造 pendingIntent。
开发建议:禁止使用空 intent 去构造 pendingIntent。
程序在加载外部 dex、so 文件是否判断文件来源、是否存放可信区域;程序删除文件是否可篡改文件路劲
是否加载公共区域程序,如 sdcard、/data/local/tmp/、应用自建立但其余应用有读写权限的目录上
是否从网络下载,检测方法包括:阅读代码、监听网路请求、见识存储区域文件读写、查看安装包
升级包是否存在公共区域存储。
在使用 getDir、getSharedPreferences(SharedPreference) 或 openFileOutput 时,若是设置了全局的可读权限,攻击者恶意读取文件内容,获取敏感信息。在设置文件属性时若是设置全局可写,攻击者可能会篡改、伪造内容,可能会进行诈骗等行为,形成用户财产损失。其中 getSharedPreferences 若是设置全局写权限,则当攻击 APP 跟被攻击 APP 具备相同的 Android:sharedUserId 属性时和签名时,攻击 APP 则能够访问到内部存储文件进行写入操做。
开发建议
使用 MODE_PRIVATE 模式建立内部存储文件
加密存储敏感数据
避免在文件中存储明文敏感信息
避免滥用 Android:sharedUserId 属性
若是两个 APP Android:sharedUserId 属性相同,切使用的签名也相同,则这两个 APP 能够互相访问内部存储文件数据
在 APP 的开发过程当中,为了方便调试,一般会使用 log 函数输出一些关键流程的信息,这些信息中一般会包含敏感内容,如执行流程、明文的用户名密码等,这会让攻击者更加容易的了解 APP 内部结构方便破解和攻击,甚至直接获取到有价值的敏感信息。
开发建议: 禁止打印敏感信息
WebView 组件中的接口函数 addJavascriptInterface 存在远程代码执行漏洞,远程攻击者利用此漏洞能实现本地 Java 和 js 的交互,可对 Android 移动终端进行网页挂马从而控制受影响设备。
Webview 接口避免使用第三方程序恶意使用发送短信,拨打电话,删除文件
修复方案: 白名单进行限制,功能仅限于该应用的功能范围以内
钓鱼这个事一直都安全界最经常使用的攻击,也是最难经过技术手段解决的一类问题,并且钓鱼的手段也是千奇百怪,要防钓鱼除了让用户提升安全意识,不点击来路不明的连接外,
技术层面能够作到以下两点:
主要是因为 JS 的 XmlHttpRequest 能够读取本地文件,从而读取到 APP data 数据库目录下的 webviewCookiesChromium.db , 这个 db 一般是系统存放 cookie 的地方,至关于变相的为读取 cookie 开了权限。
安全性要求高的应用程序必须避免使用不安全的或者强度弱的加密算法,现代计算机的计算能力使得攻击者经过暴力破解能够攻破强度弱的算法。例如,数据加密标准算法 DES(密钥默认是 56 位长度、算法半公开、迭代次数少)是极度不安全的,使用相似 EFF(Electronic Frontier Foundaton)Deep Crack 的计算机在一天内能够暴力破解由 DES 加密的消息。
开发建议:建议使用安全性更高的 AES 加密算法
在使用 RSA 加密时,密钥长度小于 512bit,小于 512 bit 的密钥很容易被破解,计算出密钥。
风险代码:
public static KeyPair getRSAKey() throws NoSuchAlgorithmException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance(RSA); keyGen.initialize(512); KeyPair key = keyGen.generateKeyPair(); return key; }
开发建议:使用 RSA 加密时,建议密钥长度大于 1024bit
AES 的 ECB 加密模式容易遭到字典攻击,安全性不够。
风险代码:
SecretKeySpec key = new SecretKeySpec(keyBytes, AES); Cipher cipher = Cipher.getInstance(AES/ECB/PKCS7Padding, BC); cipher.init(Cipher.ENCRYPT\_MODE, key);
开发建议:避免使用 ECB 模式,建议使用 CBC。
使用 IVParameterSpec 函数,若是使用了固定的初始化向量,那么密码文本可预测性高得多,容易受到字典攻击等。
风险代码:
byte[] iv = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; IvParameterSpec ips = new IvParameterSpec(iv)
复制代码开发建议
IVParameterSpec 初始化时,不使用常量 vector。
keytool 是一个 Java 数据证书的管理工具,Keytool 将密钥(key,私钥和公钥配对)和证书(certificates)存在一个称为 keystore 的文件中,并经过密码保护 keystore 中的密钥。若是密码设置过于简单,例如:12345六、android 等,则会致使 keystore 文件的私钥泄露,从而致使一系列的信息泄露风险。
开发建议:提升 keystore 保护密码的强度
在程序须要执行系统命令等函数,须要谨慎使用,严格控制命令来源,防止黑客替换命令攻击。
开发建议:严格按照要求使用
程序中重要的逻辑函数建议使用 NDK 技术经过 c/c++ 代码实现。
由于 APK 自己未进行专业加固保护,存在被 baksmali/apktool/dex2jar 直接反编译获取程序 Java 代码的风险,建议程序的重要函数使用 Android ndk 技术经过 c/c++ 实现,将重要函数编译到 so 库中,可以提升重要函数的逻辑安全强度。
发布的软件,应对 APP 进行加固,防止攻击者获取 APP 代码、业务逻辑、API 接口等,对业务和公司声誉形成必定影响,防止 APP 被破解二次打包,致使损失。
开发建议:APP 加固
整理了一些关于平时开发中会用到的知识点。须要更多相关的代码源码等等的能够讨论哦 本专栏为那些想要进阶成为高级Android工程师所准备。 从初中级转向高级工程师须要从技术的广度,深度上都有必定的造诣。因此本专栏就主要为你们分享一些技术,技术原理等。 包含源码解析,自定义View,动画实现,架构分享等。 内容难度适中,篇幅精炼,天天只需花上十几分钟阅读便可。 你们能够跟我一块儿探讨,有flutter—底层开发-性能优化—移动架构—资深UI工程师 —NDK-人工智能相关专业人员和视频教学资料 。后续还有最新鸿蒙系统相关内容分享。
欢迎加群讨论交流:765080964