首页 > IT基础架构 > 数据安全 > app安全:如何应对界面劫持、界面劫持如何检测
写这篇文章是因为,公司的项目对安全性要求较高一些,所以每年都会不定时把app提交到三方检测机构进行安全检测,其中有一项就是界面劫持风险,那么接下来,就一步步教大家怎么解决这个问题。
在android系统中,程序可以枚举当前运行的进程而不需要声明任何权限,如果攻击者注册一个receiver,响应android.intent.action.BOOT_COMPLETED,使得开启启动一个service;在这个service中启动一个计时器,不停枚举当前进程中是否有预设的进程启动,如果发现有预设进程,则使用FLAG_ACTIVITY_NEW_TASK启动自己的钓鱼界面,而正常应用的界面则隐藏在钓鱼界面的后面。
IIS7网站监控可以及时防控网站风险,快速准确监控网站是否遭到各种劫持攻击,网站在全国是否能正常打开(查看域名是否被墙),精准的DNS污染检测,具备网站打开速度检测功能,第一时间知道网站是否被黑、被入侵、被改标题、被挂黑链。精益求精的产品,缺陷为零数据提供!
它可以做到以下功能:1、检测网站是否被黑2、检测网站是否被劫持3、检测域名是否被墙4、检测DNS是否被污染5、网站真实的完全打开时间(独家)6、拥有独立监控后台,24小时定时监控域名官方地址:官方图:
这是系统漏洞,在应用程序中很难去防止这种界面支持。但应用程序自身可以增加一些防范实施。
防范实施:
1. 开启守护进程,当发现应用程序不在栈顶时,在屏幕最上层创建一个悬浮小窗口(提示信息与客户确定),以提醒用户。
2. 使用抢占式,即与劫持程序抢占栈顶。
3. 在应用切到后台时,在通知栏弹出通知提示。
以上三种防范措施都是可取的,但是其中第二种,抢占式的抢占栈顶这种做法,频繁出现的话,用户会非常反感,于是,我们最终的方案是结合第一种和第三种方法来处理:app被切到后台后Toast弹框并在通知栏显示一条通知。(提醒用户,app被切到后台运行)
示例:
@Override
protected void onPause() {
Intent intent = new Intent();
intent.putExtra("pageName", this.getComponentName()
.getPackageName());
intent.putExtra("className", this.getComponentName().getClassName());
intent.setClass(this, AppStatusService.class);
startService(intent);
}
public void onResume() {
Intent intent = new Intent();
intent.putExtra("pageName", this.getComponentName().getPackageName());
intent.putExtra("className", this.getComponentName().getClassName());
intent.setClass(this, AppStatusService.class);
stopService(intent);
}
@Override
public void onDestroy() {
Intent intent = new Intent();
intent.setClass(this, AppStatusService.class);
stopService(intent);
}
· 1
· 2
· 3
· 4
· 5
· 6
· 7
· 8
· 9
· 10
· 11
· 12
· 13
· 14
· 15
· 16
· 17
· 18
· 19
· 20
· 21
· 22
· 23
· 24
· 25
· 26
· 27
· 28
· 29
/**
* 应用是否在前台运行
*
* @return true:在前台运行;false:已经被切到后台了
*/
private boolean isAppOnForeground() {
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses != null) {
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
if (appProcess.processName.equals(packageName)) {
return true;
}
}
}
}
return false;
}
/**
* 定义一个timerTask来发通知和弹出Toast
*/
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
if (!isAppOnForeground()) {
isAppBackground = true;
//发通知
showNotification();
//弹出Toast提示
MainActivity.mCurrentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(),
getApplicationContext().getString(R.string.pervent_hijack_mes), Toast.LENGTH_SHORT)
.show();
}
});
mTimer.cancel();
}
}
};
/**
* 弹出通知提示
*/
private void showNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(
android.content.Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.icon, "xx银行", System.currentTimeMillis());
notification.defaults |= Notification.DEFAULT_VIBRATE;// 设置震动
notification.defaults |= Notification.DEFAULT_LIGHTS;// 设置LED灯提醒
notification.flags |= Notification.FLAG_NO_CLEAR;// 通知不可被状态栏的清除按钮清除掉
notification.flags |= Notification.FLAG_ONGOING_EVENT;// 通知放置在 正在运行
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.putExtra("notification", "notification");
intent.setClassName(packageName, className);
// 修改vivo手机点击通知栏不返回
intent.addCategory(Intent.CATEGORY_LAUNCHER);
// 增加Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED用于正常的从后台再次返回到原来退出时的页面中
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
PendingIntent pendingInt = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
String temp = "";
notification.setLatestEventInfo(this, "xx手机银行", "手机银行已经被切到后台运行" + temp, pendingInt);
// 设置服务的级别,使其不容易被kill掉,解决后台返回前台黑屏的问题
startForeground(1, notification);
}
· 1
· 2
· 3
· 4
· 5
· 6
· 7
· 8
· 9
· 10
· 11
· 12
· 13
· 14
· 15
· 16
· 17
· 18
· 19
· 20
· 21
· 22
· 23
· 24
· 25
· 26
· 27
· 28
· 29
· 30
· 31
· 32
· 33
· 34
· 35
· 36
· 37
· 38
· 39
· 40
· 41
· 42
· 43
· 44
· 45
· 46
· 47
· 48
· 49
· 50
· 51
· 52
· 53
· 54
· 55
· 56
· 57
· 58
· 59
· 60
· 61
· 62
· 63
· 64
· 65
· 66
· 67
· 68
· 69
· 70
· 71
· 72
@Override
public void onStart(Intent intent, int startId) {
try {
Bundle bundle = null;
if (intent != null) {
bundle = intent.getExtras();
}
if (bundle != null) {
className = bundle.getString("className");
}
// 通过计时器延迟执行
mTimer.schedule(timerTask, 50, 50);
} catch (Exception e) {
e.printStackTrace();
}
}
· 1
· 2
· 3
· 4
· 5
· 6
· 7
· 8
· 9
· 10
· 11
· 12
· 13
· 14
· 15
· 16
· 17
根据importance的不同来判断前台或后台
RunningAppProcessInfo 里面的常量IMOPORTANCE就是上面所说的前台后台,其实IMOPORTANCE是表示这个app进程的重要性,因为系统回收时候,会根据IMOPORTANCE来回收进程的。具体可以去看文档。
public static final int IMPORTANCE_BACKGROUND = 400//后台
public static final int IMPORTANCE_EMPTY = 500//空进程
public static final int IMPORTANCE_FOREGROUND =100//在屏幕最前端、可获取到焦点 可理解为Activity生命周期的OnResume();
public static final int IMPORTANCE_SERVICE = 300//在服务中
public static final int IMPORTANCE_VISIBLE = 200//在屏幕前端、获取不到焦点可理解为Activity生命周期的OnStart();
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69989270/viewspace-2738638/,如需转载,请注明出处,否则将追究法律责任。