首页 >> 大全

Android应用安全防护的点点滴滴

2023-10-07 大全 29 作者:考证青年

第二种验证证书稍微复杂一点,这种方式也只能简单的防止钓鱼,不能有效的防止钓鱼。防止钓鱼最终还是靠用户分辨,在正规渠道下载应用。

==但是如果把证书放在apk中也是一件很危险的事情,因为现在的反编译技术不得不服,所以目前觉得最好的方式,就是放在.so文件中.==可以进一步的降低风险 .

3. 通信数据尽量不使用明文形式.

前后端进行自定义算法进行加密,md5 AES RSA 等等,算法推荐.so和java相互调用的形式.

4. 防抓包

System.getProperty("http.proxyHost");  
System.getProperty("http.proxyPort");  

正常这两行代码获取的是null,如果返回不为空,就是挂代理了,那么就可以考虑是否不给数据了

5. token等等进一步的防护措施.

道高一尺,魔高一丈,未来的路还会很长.

三. 数据存储安全

有了数据就得存放,如果存放,就会被别人发现.所以得存好喽

1. 隐藏数据存储位置

在设备中,以’.'开头文件或者文件夹是不可见的,并且也可以进行读写操作.如果隐藏了存储了文件位置,就可以避免用户误操作和被发现的机会.

2. 存储内容不要使用明文

就算被找到,内容如果以密文的形式,也会降低被泄漏的风险

3. 代码中禁止硬编码重要信息内容

硬编码很容易被反编译找到.建议存储到.so中(虽然.so也可以被破解,但是相较于java更安全点)

4. 存储位置推荐

尽量存储到手机内部存储上,不要存储到外部存储卡上(因为手机内部存储只对相应的应用开放,外部存储对所有的应用都开放)

四. 组件安全

规范安卓标准组件(、、、)的访问权限

1. 设置权限开放属性::=[“true” | “false”]

属性为四大组件共有属性,其中含义大同小异。默认值由其包含 与否决定。若未包含==,默认为“false”,若存在至少一个==,则默认值为“true”。

表示是否允许外部应用组件启动。若为“false”,则 只能由同一应用或同一用户 ID 的不同应用启动。

表示是否允许外部应用组件调用服务或与其进行交互。若为“false”,则 只能由同一应用或同一用户 ID 的不同应用启动。

_滴滴安全保护_滴滴出行安全系统

表示是否可以接收来自其应用程序之外的消息,如来自系统或或其他应用的广播。若为“ false”,则广播接收器只能接收具有相同用户ID的相同应用程序或应用程序的组件发送的消息。

表示是否允许其他应用程序访问内容提供器。若为“false”,则具有与相同的用户ID(UID)的应用程序才能访问它。如果需要给其他应用程序提供内容,则应当限定读写权限。

2. 配置自定义权限

自定义权限,限制自己的组件访问,详情看自定义权限与使用

3. 使用更加安全高效的r

区别基于实现的,r 是基于实现的,拥有更高的效率与安全性。安全性主要体现在数据仅限于应用内部传输,避免广播被拦截、伪造、篡改的风险。简单了解下用法:

(1).自定义

public class MyReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//Do SomeThing Here}
}

(2).注册

MyReceiver myReceiver = new MyReceiver();
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter filter = new IntentFilter();
filter.addAction("MY_ACTION");
localBroadcastManager.registerReceiver(myReceiver, filter);

(3).发送本地广播

Bundle bundle = new Bundle();
bundle.putParcelable("DATA", content);
Intent intent = new Intent();
intent.setAction("MY_ACTION");
intent.putExtras(bundle);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

(4).在销毁时取消注册

@Override
protected 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;}

参考资料

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了