Android应用安全防护的点点滴滴( 二 )


【Android应用安全防护的点点滴滴】(4).在销毁时取消注册
@Overrideprotected void onDestroy() {super.onDestroy();localBroadcastManager.unregisterReceiver(myReceiver);}
4. 相关属性配置 (1). 属性 :=[“true” | “false”]
很多人说要在发布的时候手动设置该值为false,其实根据官方文档说明,默认值就是false 。
(2). 属性 :=[“true” | “false”]
设置是否支持备份,默认值为true,应当慎重支持该属性,避免应用内数据通过备份造成的泄漏问题 。
5. 自定义键盘.
对于操作密码等危险输入的情况,可以考虑自定义键盘处理,防止通过键盘被盗用密码.
五. 其他防护措施
多做一层安全措施,少一点风险.
1. 代码安全2. 控制日志输出
自定义工具类,不要在线上出现敏感的信息
3. 漏洞检测工具
各种云测平台进行测试
4. 防止模拟器
判断手机是否包含蓝牙等模块,一些信息是否跟手机真机不一致等.防止通过模拟器篡改信息
5. 二次打包
通过判断签名信息,防止,被二次打包,调试应用信息
6. 账号与设备绑定
账号与相应设备进行绑定,如果发现与常用设备不符合,增加短信登录形式进行重新登录
7. dex文件的校验
重编译apk其实就是重编译了.dex文件,重编译后,生成的.dex文件的hash值就改变了,因此我们可以通过检测安装后.dex文件的hash值来判断apk是否被重打包过 。
(1). 读取应用安装目录下/data/app/xxx.apk中的.dex文件并计算其哈希值,将该值与软件发布时的.dex哈希值做比较来判断客户端是否被篡改 。
(2). 读取应用安装目录下/data/app/xxx.apk中的META-INF目录下的.MF文件,该文件详细记录了apk包中所有文件的哈希值,因此可以读取该文件获取到.dex文件对应的哈希值,将该值与软件发布时的.dex哈希值做比较就可以判断客户端是否被篡改 。
为了防止被破解,软件发布时的.dex哈希值应该存放在服务器端 。
8.调试器检测
为了防止apk被动态调试,可以检测是否有调试器连接 。在类中提供了()方法用于检测是否有调试器连接,如果发现有调试器连接,可以直接退出程序 。
9.是否root
检测是否包含su程序,和ro.是否为1,如果root了,可以禁止某些核心功能
检测是否root的代码
public boolean isRoot() {int secureProp = getroSecureProp();if (secureProp == 0)//eng/userdebug版本,自带root权限return true;else return isSUExist();//user版本,继续查su文件}private int getroSecureProp() {int secureProp;String roSecureObj = CommandUtil.getSingleInstance().getProperty("ro.secure");if (roSecureObj == null) secureProp = 1;else {if ("0".equals(roSecureObj)) secureProp = 0;else secureProp = 1;}return secureProp;}private boolean isSUExist() {File file = null;String[] paths = {"/sbin/su","/system/bin/su","/system/xbin/su","/data/local/xbin/su","/data/local/bin/su","/system/sd/xbin/su","/system/bin/failsafe/su","/data/local/su"};for (String path : paths) {file = new File(path);if (file.exists()) return true;//可以继续做可执行判断}return false;}
10. 是否装有xposd框架
检测是否安装有xposd框架,如果有提示并隐藏核心功能模块.接口禁用某些功能
所有的方案回归到一点:判断的包是否存在 。
(1).是通过主动抛出异常查栈信息;
(2).是主动反射调用 。
private static final String XPOSED_HELPERS = "de.robv.android.xposed.XposedHelpers";private static final String XPOSED_BRIDGE = "de.robv.android.xposed.XposedBridge";//手动抛出异常,检查堆栈信息是否有xp框架包public boolean isEposedExistByThrow() {try {throw new Exception("gg");} catch (Exception e) {for (StackTraceElement stackTraceElement : e.getStackTrace()) {if (stackTraceElement.getClassName().contains(XPOSED_BRIDGE)) return true;}return false;}}//检查xposed包是否存在public boolean isXposedExists() {try {Object xpHelperObj = ClassLoader.getSystemClassLoader().loadClass(XPOSED_HELPERS).newInstance();} catch (InstantiationException e) {e.printStackTrace();return true;} catch (IllegalAccessException e) {//实测debug跑到这里报异常e.printStackTrace();return true;} catch (ClassNotFoundException e) {e.printStackTrace();return false;}try {Object xpBridgeObj = ClassLoader.getSystemClassLoader().loadClass(XPOSED_BRIDGE).newInstance();} catch (InstantiationException e) {e.printStackTrace();return true;} catch (IllegalAccessException e) {//实测debug跑到这里报异常e.printStackTrace();return true;} catch (ClassNotFoundException e) {e.printStackTrace();return false;}return true;}//尝试关闭xp的全局开关,亲测可用public boolean tryShutdownXposed() {if (isEposedExistByThrow()) {Field xpdisabledHooks = null;try {xpdisabledHooks = ClassLoader.getSystemClassLoader().loadClass(XPOSED_BRIDGE).getDeclaredField("disableHooks");xpdisabledHooks.setAccessible(true);xpdisabledHooks.set(null, Boolean.TRUE);return true;} catch (NoSuchFieldException e) {e.printStackTrace();return false;} catch (ClassNotFoundException e) {e.printStackTrace();return false;} catch (IllegalAccessException e) {e.printStackTrace();return false;}} else return true;}