Аудит доступа к данным

Вы можете получить представление о том, как ваше приложение и его зависимости получают доступ к личным данным пользователей, выполнив аудит доступа к данным . Этот процесс, доступный на устройствах под управлением Android 11 (уровень API 30) и выше, позволяет лучше выявлять потенциально непредвиденный доступ к данным. Ваше приложение может зарегистрировать экземпляр AppOpsManager.OnOpNotedCallback , который может выполнять действия каждый раз при наступлении одного из следующих событий:

  • Код вашего приложения обращается к конфиденциальным данным. Чтобы определить, какая логическая часть приложения вызвала событие, вы можете провести аудит доступа к данным по тегу атрибуции .
  • Код в зависимой библиотеке или SDK получает доступ к частным данным.

Аудит доступа к данным вызывается в потоке, в котором выполняется запрос данных. Это означает, что если сторонний SDK или библиотека в вашем приложении вызывает API, который обращается к приватным данным, аудит доступа к данным позволяет вашему OnOpNotedCallback проверить информацию о вызове. Обычно этот объект обратного вызова может определить, исходил ли вызов из вашего приложения или из SDK, анализируя текущее состояние приложения, например, трассировку стека текущего потока.

Журнал доступа к данным

Чтобы выполнить аудит доступа к данным с использованием экземпляра AppOpsManager.OnOpNotedCallback , реализуйте логику обратного вызова в компоненте, в котором вы собираетесь проводить аудит доступа к данным, например, в методе onCreate() действия или методе onCreate() приложения.

Следующий фрагмент кода определяет AppOpsManager.OnOpNotedCallback для аудита доступа к данным в рамках одного действия:

Котлин

override fun onCreate(savedInstanceState: Bundle?) {     val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() {         private fun logPrivateDataAccess(opCode: String, trace: String) {             Log.i(MY_APP_TAG, "Private data accessed. " +                     "Operation: $opCode\nStack Trace:\n$trace")         }          override fun onNoted(syncNotedAppOp: SyncNotedAppOp) {             logPrivateDataAccess(                     syncNotedAppOp.op, Throwable().stackTrace.toString())         }          override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) {             logPrivateDataAccess(                     syncNotedAppOp.op, Throwable().stackTrace.toString())         }          override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {             logPrivateDataAccess(asyncNotedAppOp.op, asyncNotedAppOp.message)         }     }      val appOpsManager =             getSystemService(AppOpsManager::class.java) as AppOpsManager     appOpsManager.setOnOpNotedCallback(mainExecutor, appOpsCallback) }

Ява

@Override public void onCreate(@Nullable Bundle savedInstanceState,         @Nullable PersistableBundle persistentState) {     AppOpsManager.OnOpNotedCallback appOpsCallback =             new AppOpsManager.OnOpNotedCallback() {         private void logPrivateDataAccess(String opCode, String trace) {             Log.i(MY_APP_TAG, "Private data accessed. " +                     "Operation: $opCode\nStack Trace:\n$trace");         }          @Override         public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {             logPrivateDataAccess(syncNotedAppOp.getOp(),                     Arrays.toString(new Throwable().getStackTrace()));         }          @Override         public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {             logPrivateDataAccess(syncNotedAppOp.getOp(),                     Arrays.toString(new Throwable().getStackTrace()));         }          @Override         public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) {             logPrivateDataAccess(asyncNotedAppOp.getOp(),                     asyncNotedAppOp.getMessage());         }     };      AppOpsManager appOpsManager = getSystemService(AppOpsManager.class);     if (appOpsManager != null) {         appOpsManager.setOnOpNotedCallback(getMainExecutor(), appOpsCallback);     } }

Методы onAsyncNoted() и onSelfNoted() вызываются в определенных ситуациях:

  • onAsyncNoted() вызывается, если доступ к данным не происходит во время вызова API вашего приложения. Наиболее распространённый пример — когда приложение регистрирует прослушиватель, и доступ к данным происходит каждый раз при вызове обратного вызова прослушивателя.

    Аргумент AsyncNotedOp , передаваемый в onAsyncNoted() содержит метод getMessage() . Этот метод предоставляет дополнительную информацию о доступе к данным. В случае обратных вызовов местоположения сообщение содержит хэш системной идентификации прослушивателя.

  • onSelfNoted() вызывается в очень редком случае, когда приложение передает свой собственный UID в noteOp() .

Аудит доступа к данным по тегу атрибуции

У вашего приложения может быть несколько основных вариантов использования, например, чтобы пользователи могли делать фотографии и делиться ими со своими контактами. Если вы разрабатываете многоцелевое приложение, вы можете применить тег атрибуции к каждой его части при аудите доступа к данным. Контекст attributionTag возвращается в объектах, передаваемых в вызовы onNoted() . Это помогает вам легче отслеживать доступ к данным вплоть до логических частей кода.

Чтобы определить теги атрибуции в вашем приложении, выполните действия, описанные в следующих разделах.

Объявить теги атрибуции в манифесте

Если ваше приложение предназначено для Android 12 (уровень API 31) или выше, необходимо объявить теги атрибуции в файле манифеста приложения, используя формат, показанный в следующем фрагменте кода. При попытке использовать тег атрибуции, не объявленный в файле манифеста приложения, система создаст для вас null тег и запишет сообщение в Logcat.

<manifest ...>     <!-- The value of "android:tag" must be a literal string, and the          value of "android:label" must be a resource. The value of          "android:label" is user-readable. -->     <attribution android:tag="sharePhotos"                  android:label="@string/share_photos_attribution_label" />     ... </manifest>

Создайте теги атрибуции

В методе onCreate() действия, в котором вы получаете доступ к данным, например, в действии, в котором вы запрашиваете местоположение или получаете доступ к списку контактов пользователя, вызовите createAttributionContext() , передав ему тег атрибуции, который вы хотите связать с частью своего приложения.

В следующем фрагменте кода показано, как создать тег атрибуции для части приложения, которая позволяет делиться местоположением фотографий:

Котлин

class SharePhotoLocationActivity : AppCompatActivity() {     lateinit var attributionContext: Context      override fun onCreate(savedInstanceState: Bundle?) {         attributionContext = createAttributionContext("sharePhotos")     }      fun getLocation() {         val locationManager = attributionContext.getSystemService(                 LocationManager::class.java) as LocationManager         // Use "locationManager" to access device location information.     } }

Ява

public class SharePhotoLocationActivity extends AppCompatActivity {     private Context attributionContext;      @Override     public void onCreate(@Nullable Bundle savedInstanceState,             @Nullable PersistableBundle persistentState) {         attributionContext = createAttributionContext("sharePhotos");     }      public void getLocation() {         LocationManager locationManager =                 attributionContext.getSystemService(LocationManager.class);         if (locationManager != null) {             // Use "locationManager" to access device location information.         }     } }

Включать теги атрибуции в журналы доступа

Обновите обратный вызов AppOpsManager.OnOpNotedCallback , чтобы журналы вашего приложения включали имена определенных вами тегов атрибуции.

В следующем фрагменте кода показана обновленная логика, которая регистрирует теги атрибуции:

Котлин

val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() {     private fun logPrivateDataAccess(             opCode: String, attributionTag: String, trace: String) {         Log.i(MY_APP_TAG, "Private data accessed. " +                     "Operation: $opCode\n " +                     "Attribution Tag:$attributionTag\nStack Trace:\n$trace")     }      override fun onNoted(syncNotedAppOp: SyncNotedAppOp) {         logPrivateDataAccess(syncNotedAppOp.op,                 syncNotedAppOp.attributionTag,                 Throwable().stackTrace.toString())     }      override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) {         logPrivateDataAccess(syncNotedAppOp.op,                 syncNotedAppOp.attributionTag,                 Throwable().stackTrace.toString())     }      override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {         logPrivateDataAccess(asyncNotedAppOp.op,                 asyncNotedAppOp.attributionTag,                 asyncNotedAppOp.message)     } }

Ява

@Override public void onCreate(@Nullable Bundle savedInstanceState,         @Nullable PersistableBundle persistentState) {     AppOpsManager.OnOpNotedCallback appOpsCallback =             new AppOpsManager.OnOpNotedCallback() {         private void logPrivateDataAccess(String opCode,                 String attributionTag, String trace) {             Log.i("MY_APP_TAG", "Private data accessed. " +                     "Operation: $opCode\n " +                     "Attribution Tag:$attributionTag\nStack Trace:\n$trace");         }          @Override         public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {             logPrivateDataAccess(syncNotedAppOp.getOp(),                     syncNotedAppOp.getAttributionTag(),                     Arrays.toString(new Throwable().getStackTrace()));         }          @Override         public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {             logPrivateDataAccess(syncNotedAppOp.getOp(),                     syncNotedAppOp.getAttributionTag(),                     Arrays.toString(new Throwable().getStackTrace()));         }          @Override         public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) {             logPrivateDataAccess(asyncNotedAppOp.getOp(),                     asyncNotedAppOp.getAttributionTag(),                     asyncNotedAppOp.getMessage());         }     };      AppOpsManager appOpsManager = getSystemService(AppOpsManager.class);     if (appOpsManager != null) {         appOpsManager.setNotedAppOpsCollector(appOpsCollector);     } }