2. Android中已经定义了permission这个概念来管理系统中的权限,但是一个恶意程序可能会申请超过其需求不必要的权限,获取用户信息,对手机进行破坏等等,怎么样能够更严格的控制系统中的行为?有三个方案:
a) Android不是定义了permission吗?我们可以通过去除恶意App的权限,达到控制的目的。但是这样会带来一个问题,当该App需要访问资源时AMS会checkPermission,如果它的permission被去除了,系统就会抛exception,app可能会crash。这样带来的用户体验不好,用户会说App正在运行怎么出错停止运行了?
b) 在系统中访问特定资源的地方加hook,如果不允许该app访问资源,返回无效值,使其得不到有用信息或者无法写入信息。 Hook通过root,进程注入的方式实现。此方案的缺点是系统需要root,而root会给手机带来很多风险,所有app都可以获取最高root权限。市面上的手机安全软件都是通过这种方式,不root就不能进行权限控制。
c) 如果系统本身已经拥有这样的hook点,则不需要root也可以实现权限控制。具体做法是单独运行一个安全进程,如果有访问资源的行为,从hook点发起IPC调用到安全进程,安全进程根据访问者的package name,uid,pid等信息决定允不允许访问。这是我们的方案,系统内部已经集成了安全机制,真正做到不root也安全的Android系统。
3. 那么我们就来看看哪些权限是用户关心的,怎么处理才可以满足权限控制需求并获得最佳体验。首先是一些敏感数据。
a) 数据库信息,比如联系人信息,通话记录,短信等。这些信息都是很重要的,而很多app在自己功能之外额外的申请访问这些资源。我们知道这些信息在Android中是以provider的形式存储,通过ContentResovler访问,可以拥有query,Insert,delete,update操作。不同信息在数据库中通过URL区分,每一条记录是一行,通过检测判断URL和App信息,决定允不允许读写。
i. query操作
通过特定URL查询,返回对应Cursor。如果禁止此次查询,可以返回一个WrapCursor,该Cursor是对原来信息的封装,App拿到之后获取不到里面的任何信息,没有行、列,任何操作都会返回无效值。
ii. insert操作
往对应URL中插入一行,返回插入后的那一行。如果禁止此次写操作,返回null,不执行插入操作。
iii. delete操作
将对应URL中删除若干行,返回删除行数。如果禁止删除,返回 -1 ,不删除任何内容。
iv. update操作
更新URL中的若干行,返回更新行数。如果禁止更新,返回 -1 ,不进行任何更新。
b) 手机中有很多跟硬件相关信息,比如IMSI,IMEI,手机号码等。这些信息标示着这部手机在网络中的身份。通过TelephonyManger拿到手机信息PhoneSubInfo,再使用PhoneSubInfo的方法获取对应信息。不想让App获取这些有用信息,只要在PhoneSubInfo的这些方法中返回null就可以。
i. IMEI: 国际移动设备身份码,与每台手机一一对应,而且该码是全世界唯一的。PhoneSubInfo的getDeviceId方法获取。
ii. IMSI: 国际移动用户识别码,区别移动用户的标志,储存在SIM卡中,可用于区别移动用户的有效信息。PhoneSubInfo的getSubscriberId方法获取。
iii. 手机号码。PhoneSubInfo的getLine1number方法获取。
c) Android中有两种跟手机位置相关的信息,一种是通过GPS获取的精确位置信息(FINE_LOCATION) ,一种是通过基站获取的粗略位置信息(COARSE_LOCATION) 。具体实现是App通过LocationManager的requestLocationUpdate方法注册一个listener,当位置信息变化时通知App。用户可能不希望暴露自己的位置,那么可以在此方法中真正注册listener之前返回,使App无法获取手机位置信息。
4. Android手机中的敏感行为:
a) 打电话。一个哪怕是后台的service都可以申请这个权限,并且偷偷的打电话,而用户只想让特定软件具有该功能,比如系统自带的phone。如何控制打电话权限呢?打电话实际上最终通过startActivity(Intent(ACTION_CALL))启动Phone App的呼叫界面,进行拨号。如果我们禁止打电话,只要在AMS中startActivity这个动作真正执行之前返回就可以了。
b) 电话录音。这个权限比打电话还要危险,因为打电话还要弹出系统呼叫界面,而录音则可以静默执行。如果有恶意程序在后台录音,会造成用户隐私甚至是商业秘密等泄露。对通话进行录音要通过MediaRecorder对象来操作,设置录音来源为电话setAudioSource(VOICE_CALL)。如果要禁止,在其开始录音(MediaRecorder.start)真正执行之前返回,或者使其无法正常start。
c) 发短信。很多App都申请这个权限,大都是为了方便用户使用其服务,但是也不乏发短信扣费的服务,如果用户玩游戏时不小心点了某个窗口就有可能定制了某服务,几块钱就花出去了。更严重的是App可以悄悄地在后台发送短信,导致用户信息泄露。发送短信需要通过SmsManager提供的send方法,在真正开始发送之前检查发送发起者是否合法,如果禁止就返回,使发送动作没有真正执行。