Definiowanie niestandardowych uprawnień aplikacji

Ten dokument opisuje, jak deweloperzy aplikacji mogą definiować własne uprawnienia za pomocą funkcji zabezpieczeń udostępnianych przez Androida. Gdy zdefiniujesz uprawnienia niestandardowe, aplikacja może udostępniać swoje zasoby i możliwości innym aplikacjom. Więcej informacji o uprawnieniach znajdziesz w omówieniu uprawnień.

Tło

Android to system operacyjny z oddzielnymi uprawnieniami, w którym każda aplikacja działa z odrębną tożsamością systemową (identyfikatorem użytkownika i identyfikatorem grupy w systemie Linux). Części systemu są też rozdzielone na osobne tożsamości. W ten sposób Linux izoluje aplikacje od siebie nawzajem i od systemu.

Aplikacje mogą udostępniać swoje funkcje innym aplikacjom, definiując uprawnienia, o które mogą prosić inne aplikacje. Mogą też definiować uprawnienia, które są automatycznie udostępniane wszystkim innym aplikacjom podpisanym tym samym certyfikatem.

Podpisywanie aplikacji

Wszystkie pliki APK muszą być podpisane certyfikatem, którego klucz prywatny należy do dewelopera. Certyfikat nie musi być podpisany przez urząd certyfikacji. Korzystanie z podpisanych samodzielnie certyfikatów jest dozwolone i typowe dla aplikacji na Androida. Certyfikaty na Androidzie służą do rozróżniania autorów aplikacji. Dzięki temu system będzie mógł przyznawać i odmawiać aplikacjom dostęp do uprawnień na poziomie podpisu oraz przyznawać i odrzucać żądanie aplikacji o przyznanie tej samej tożsamości w systemie Linux co innej aplikacji.

Przyznaj uprawnienia do podpisu po zakończeniu produkcji urządzenia

Począwszy od Androida 12 (poziom interfejsu API 31) atrybut knownCerts uprawnień na poziomie podpisu umożliwia odwoływanie się do skrótów znanych certyfikatów podpisywania w czasie deklaracji.

Możesz zadeklarować atrybut knownCerts i użyć flagi knownSigner w atrybucie protectionLevel aplikacji, aby uzyskać określone uprawnienia na poziomie podpisu. Następnie system przyznaje te uprawnienia aplikacji wysyłającej żądanie, jeśli dowolny sygnatariusz w historii podpisywania aplikacji wysyłającej żądanie (w tym obecny sygnatariusz) pasuje do jednego z skrótów zadeklarowanych z uprawnieniami w atrybucie knownCerts.

Flaga knownSigner umożliwia urządzeniom i aplikacjom przyznawanie uprawnień do podpisu innym aplikacjom bez konieczności podpisywania aplikacji podczas produkcji i dostawy urządzenia.

Identyfikatory użytkowników i dostęp do plików

Podczas instalacji Android nadaje każdemu pakietowi inny identyfikator użytkownika systemu Linux. Tożsamość pozostaje stała przez cały okres życia pakietu na urządzeniu. Na innym urządzeniu ten sam pakiet może mieć inny identyfikator UID. Ważne jest, aby każdy pakiet miał inny identyfikator na danym urządzeniu.

Egzekwowanie zabezpieczeń odbywa się na poziomie procesu, dlatego kod dowolnych 2 pakietów nie może normalnie działać w tym samym procesie, ponieważ muszą one działać jako różni użytkownicy Linuksa.

Wszelkie dane przechowywane przez aplikację są przypisywane do jej identyfikatora użytkownika i nie są normalnie dostępne dla innych pakietów.

Więcej informacji o modelu zabezpieczeń Androida znajdziesz w artykule Omówienie bezpieczeństwa Androida.

Definiowanie i egzekwowanie uprawnień

Aby egzekwować własne uprawnienia, musisz najpierw zadeklarować je w AndroidManifest.xml, używając co najmniej 1 elementu <permission>.

Konwencja nazewnictwa

System nie zezwala na deklarowanie uprawnień o tej samej nazwie przez wiele pakietów, chyba że wszystkie pakiety są podpisane tym samym certyfikatem. Jeśli pakiet deklaruje uprawnienia, system nie zezwoli użytkownikowi na instalowanie innych pakietów z tą samą nazwą uprawnienia, chyba że pakiety te są podpisane tym samym certyfikatem co pierwszy pakiet.

Zalecamy, aby na początku uprawnień znajdować się nazwa pakietu aplikacji, odwrotna nazwa domeny, odwrotna nazwa domeny, .permission., a następnie opis funkcji reprezentowanej przez uprawnienie (w górnej części SNAKE_CASE). Przykład: com.example.myapp.permission.ENGAGE_HYPERSPACE.

Przestrzeganie tej zalecenia pozwala uniknąć kolizji z nazwami i ułatwia jasne zidentyfikowanie właściciela oraz zamiaru korzystania z uprawnienia niestandardowego.

Przykład

Na przykład aplikacja, która musi kontrolować, które inne aplikacje mogą uruchamiać określone działania, może zadeklarować uprawnienia do tej operacji w ten sposób:

<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.myapp" >
    
    <permission
      android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
      android:label="@string/permlab_deadlyActivity"
      android:description="@string/permdesc_deadlyActivity"
      android:permissionGroup="android.permission-group.COST_MONEY"
      android:protectionLevel="dangerous" />
    ...
</manifest>

Atrybut protectionLevel jest wymagany i informuje system, jak poinformować użytkowników o aplikacjach wymagających uprawnień lub które aplikacje mogą je posiadać, zgodnie z opisem w linkowanej dokumentacji.

Atrybut android:permissionGroup jest opcjonalny i służy jedynie do ułatwienia systemowi wyświetlania uprawnień użytkownika. W większości przypadków określasz to ustawienie jako standardową grupę systemową (podaną w sekcji android.Manifest.permission_group), ale możesz ją też zdefiniować samodzielnie zgodnie z opisem w następnej sekcji. Zalecamy użycie istniejącej grupy, ponieważ upraszcza to interfejs uprawnień wyświetlany użytkownikowi.

Musisz podać zarówno etykietę, jak i opis uprawnienia. Są to zasoby w postaci ciągu znaków, które użytkownik widzi podczas wyświetlania listy uprawnień (android:label) lub szczegółów pojedynczego uprawnienia (android:description). Etykieta jest krótka: kilka słów opisujących kluczową funkcję chronioną przez uprawnienie. Opis składa się z kilku zdań opisujących uprawnienia danej osoby. Nasza konwencja składa się z dwuzdaniowego opisu, w którym pierwsze z nich opisuje uprawnienie, a drugie ostrzega użytkownika o tym, co może pójść nie tak, gdy aplikacja otrzyma dane uprawnienie.

Oto przykład etykiety i opisu uprawnienia CALL_PHONE:

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the app to call non-emergency
phone numbers without your intervention. Malicious apps may cause unexpected
calls on your phone bill.</string>

Utwórz grupę uprawnień

Jak wspomnieliśmy w poprzedniej sekcji, możesz użyć atrybutu android:permissionGroup, aby ułatwić systemowi opisanie uprawnień użytkownikowi. W większości przypadków określasz to ustawienie jako standardową grupę systemową (podaną w sekcji android.Manifest.permission_group), ale możesz też zdefiniować własną grupę za pomocą polecenia <permission-group>.

Element <permission-group> definiuje etykietę zestawu uprawnień – zarówno tych zadeklarowanych w pliku manifestu z elementami <permission>, jak i tych zadeklarowanych w innym miejscu. Ma to wpływ tylko na sposób grupowania uprawnień wyświetlanych użytkownikowi. Element <permission-group> nie określa uprawnień należących do grupy, ale nadaje grupie nazwę.

Możesz do niej dodać uprawnienie, przypisując nazwę grupy do atrybutu <permission> elementu permissionGroup.

Element <permission-tree> deklaruje przestrzeń nazw dla grupy uprawnień zdefiniowanych w kodzie.

Rekomendacje dotyczące uprawnień niestandardowych

Aby zdefiniować niestandardowe uprawnienia aplikacji i prosić inne aplikacje o uprawnienia niestandardowe, zdefiniuj elementy <uses-permission>. Warto jednak dokładnie ocenić, czy jest to w przypadku konieczne.

  • Jeśli projektujesz pakiet aplikacji, które zapewniają sobie dostęp do różnych funkcji, spróbuj tak zaprojektować aplikacje, aby każde uprawnienie było zdefiniowane tylko raz. Musisz to zrobić, jeśli wszystkie aplikacje nie są podpisane tym samym certyfikatem. Nawet jeśli wszystkie aplikacje są podpisane tym samym certyfikatem, najlepiej jest zdefiniować wszystkie uprawnienia tylko raz.
  • Jeśli ta funkcja jest dostępna tylko w aplikacjach podpisanych tym samym podpisem co aplikacja udostępniająca, możesz uniknąć definiowania uprawnień niestandardowych przez sprawdzanie podpisu. Gdy jedna z aplikacji wysyła żądanie do innej, druga aplikacja może przed wykonaniem żądania sprawdzić, czy obie są podpisane tym samym certyfikatem.

Jeśli potrzebne jest uprawnienie niestandardowe, zastanów się, czy dostęp do niego muszą mieć tylko aplikacje podpisane przez tego samego programistę, co sprawdza uprawnienia. Dotyczy to na przykład implementowania bezpiecznej komunikacji międzyprocesowej między 2 aplikacjami tego samego programisty. Jeśli tak jest, zalecamy skorzystanie z uprawnień do podpisywania. Uprawnienia do podpisu są przejrzyste dla użytkownika i unikają uprawnień potwierdzonych przez użytkowników, co może być dla nich mylące.

Przeczytaj więcej na temat:

<uses-permission>
Dokumentacja API dotycząca tagu manifestu, która deklaruje wymagane uprawnienia systemowe aplikacji.

Być może zainteresują Cię również:

Omówienie bezpieczeństwa Androida
Szczegółowa dyskusja na temat modelu zabezpieczeń platformy Androida.