当前位置:   article > 正文

Android安全开发之 Provider 组件安全_android provider

android provider

Android系统中的Content Provider组件是一种用于在不同应用之间共享数据的机制。它提供了一种安全、可控的方式,允许应用访问其他应用的数据。然而,如果Provider组件的安全措施没有得到妥善实现,则可能会导致严重的安全漏洞,例如数据泄露、隐私侵犯甚至恶意代码执行。

一、安全渗透案例

测试步骤:

1.进入应用进行添加新内容,插入数据库

2.使用adb或者编写apk,对指定uri进行查询

1.adb shell content query --uri content://com.xxx.note.data.NoteProvider/note

测试结论:

编辑内容都会通过uri查询出来,泄露用户隐私信息,未鉴权

server@dev-fj-srv:~/Desktop $ adb shell content query --uri content://com.xxx.note.data.NoteProvider/note
Row: 0 _id=1, title=, content=<?xml version="1.0" encoding="UTF-8"?><note><notetxt>地址</notetxt></note>, longdate=1717745973845, iscollect=0, iscontainpic=0, isprivate=0, isdeleted=0, backgroundid=4, parentfolderid=-10, istop=0, topdate=0, iscontainvoice=0, picpath=NULL
Row: 1 _id=2, title=, content=<?xml version="1.0" encoding="UTF-8"?><note><notetxt>账户</notetxt></note>, longdate=1717745961274, iscollect=0, iscontainpic=0, isprivate=0, isdeleted=0, backgroundid=4, parentfolderid=-10, istop=0, topdate=0, iscontainvoice=0, picpath=NULL
Row: 2 _id=3, title=, content=<?xml version="1.0" encoding="UTF-8"?><note><notetxt>密码</notetxt></note>, longdate=1717745951538, iscollect=0, iscontainpic=0, isprivate=0, isdeleted=0, backgroundid=4, parentfolderid=-10, istop=0, topdate=0, iscontainvoice=0, picpath=NULL
  • 1
  • 2
  • 3
  • 4

漏洞修复建议:

增加鉴权校验

很多人可能会好奇,我的代码进行了混淆处理,如何发现我的provider及其authorities,可以通过APK文件进行逆向或反编译出AndroidManifest.xml,此类声明信息是不会被混淆的,可以直接获取的。

甚至可以直接通过adb获取:adb dumpsys package com.xxx.note 直接获取得到 ContentProvider Authorities

ContentProvider Authorities:
  [com.xxx.note.data.SearchProvider]:
    Provider{fc33540 com.xxx.note/.data.SearchProvider}
      applicationInfo=ApplicationInfo{5ba67a5 com.xxx.note}
  [com.xxx.note.provider]:
    Provider{19d68c3 com.xxx.note/androidx.core.content.FileProvider}
      applicationInfo=ApplicationInfo{a90977a com.xxx.note}
  [com.xxx.note.data.NoteProvider]:
    Provider{da7fc72 com.xxx.note/.data.NoteProvider}
      applicationInfo=ApplicationInfo{13db2b com.xxx.note}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

二、解决方案

2.1 无需 exported

当 ContentProvider 仅应用自身使用,无需 exported 供其他应用调用,即可直接设置 exported="false"

<provider
    android:name=".data.NoteProvider"
    android:authorities="com.xxx.note.data.NoteProvider"
    android:exported="false" />
  • 1
  • 2
  • 3
  • 4

此时再通过 adb 命令查询就会出现 SecurityException 报错无法查询

server@dev-fj-srv:~/Desktop$ adb shell content query --uri content://com.xxx.note.data.NoteProvider/note
Error while accessing provider:com.xxx.note.data.NoteProvider
java.lang.SecurityException: Permission Denial: opening provider com.xxx.note.data.NoteProvider from (null) (pid=10781, uid=2000) that is not exported from UID 10196
	at android.os.Parcel.createExceptionOrNull(Parcel.java:3057)
	at android.os.Parcel.createException(Parcel.java:3041)
	at android.os.Parcel.readException(Parcel.java:3024)
	at android.os.Parcel.readException(Parcel.java:2966)
	at android.app.IActivityManager$Stub$Proxy.getContentProviderExternal(IActivityManager.java:7803)
	at com.android.commands.content.Content$Command.execute(Content.java:516)
	at com.android.commands.content.Content.main(Content.java:735)
	at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
	at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:447)
Caused by: android.os.RemoteException: Remote stack trace:
	at com.android.server.am.ContentProviderHelper.checkAssociationAndPermissionLocked(ContentProviderHelper.java:756)
	at com.android.server.am.ContentProviderHelper.getContentProviderImpl(ContentProviderHelper.java:411)
	at com.android.server.am.ContentProviderHelper.getContentProviderExternalUnchecked(ContentProviderHelper.java:182)
	at com.android.server.am.ContentProviderHelper.getContentProviderExternal(ContentProviderHelper.java:176)
	at com.android.server.am.ActivityManagerService.getContentProviderExternal(ActivityManagerService.java:6889)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2.2 需要 exported

当 ContentProvider 需要通过数据接口供其他应用使用时,就只能设置exported="true",这个时候我们需要添加鉴权校验或包名过滤。

 <provider
     android:name=".data.SearchProvider"
     android:authorities="com.xxx.note.data.SearchProvider"
     android:exported="true"/>
  • 1
  • 2
  • 3
  • 4

在重写 ContentProvider query 方法时先进行校验,验证成功后再返回查询数据。

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    if (!isAuthorized()) {
        throw new SecurityException("Access denied. Unauthorized.");
    }
    // 返回数据查询
}

private boolean isAuthorized() {
    return AUTHORIZE_ACCESS_PACKAGE.equals(getCallingPackage());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

AUTHORIZE_ACCESS_PACKAGE 即为允许访问此 ContentProvider 的应用包名。

此时再通过 adb 命令访问此 ContentProvider 就会返回 java.lang.SecurityException: Access denied. Unauthorized. 报错。通过 adb 访问时候可以查询到 getCallingPackage() 为 com.android.shell,不在我们运行访问的包名名单内。

server@dev-fj-srv:~/Desktop$ adb shell content query --uri content://com.xxx.note.data.SearchProvider
Error while accessing provider:com.xxx.note.data.SearchProvider
java.lang.SecurityException: Access denied. Unauthorized.
	at android.os.Parcel.createExceptionOrNull(Parcel.java:3057)
	at android.os.Parcel.createException(Parcel.java:3041)
	at android.os.Parcel.readException(Parcel.java:3024)
	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)
	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
	at android.content.ContentProviderProxy.query(ContentProviderNative.java:495)
	at com.android.commands.content.Content$QueryCommand.onExecute(Content.java:661)
	at com.android.commands.content.Content$Command.execute(Content.java:522)
	at com.android.commands.content.Content.main(Content.java:735)
	at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
	at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:447)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

三、正确的定义私有权限

在AndroidManifest中定义私有权限的语法为:
img

其中android:protectionLevel的可选值分别表示:

  • normal:默认值,低风险权限,在安装的时候,系统会自动授予权限给 application。
  • dangerous:高风险权限,如发短信,打电话,读写通讯录。使用此protectionLevel来标识用户可能关注的一些权限。Android将会在安装程序时,警示用户关于这些权限的需求,具体的行为可能依据Android版本或者所安装的移动设备而有所变化。
  • signature: 签名权限,在其他 app 引用声明的权限的时候,需要保证两个 app 的签名一致。这样系统就会自动授予权限给第三方 app,而不提示给用户。
  • signatureOrSystem:除了具有相同签名的APP可以访问外,Android系统中的程序有权限访问。

大部分开放的Provider,是提供给本公司的其他应用使用的,一般的话一个公司打包签名APP的签名证书都应该是一致的,这种情况下,Provider的android:protectionLevel应为设为“signature”。

四、Provider 组件的安全风险

  1. 权限控制不当:如果Provider组件没有正确配置权限,则可能会允许未经授权的应用访问敏感数据。
  2. 数据泄露:Provider组件可能会被恶意应用利用来窃取敏感数据,例如联系人信息、通话记录、短信内容等。
  3. 隐私侵犯:Provider组件可能会被恶意应用利用来跟踪用户行为,例如位置信息、浏览历史等。
  4. 恶意代码执行:Provider组件可能会被恶意应用利用来执行恶意代码,例如植入病毒、木马等。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/892132
推荐阅读
相关标签
  

闽ICP备14008679号