Definiowanie niestandardowych uprawnień aplikacji

W tym dokumencie opisaliśmy, jak deweloperzy aplikacji mogą korzystać z funkcji bezpieczeństwa Androida, aby definiować własne uprawnienia. Definiując niestandardowe uprawnienia, aplikacja może udostępniać swoje zasoby i możliwości innym aplikacjom. Więcej informacji o uprawnieniach znajdziesz w artykule Omówienie uprawnień.

Tło

Android to system operacyjny z oddzielonymi uprawnieniami, w którym każda aplikacja działa z osobną tożsamością systemową (identyfikator użytkownika i grupy w systemie Linux). Poszczególne części systemu są też rozdzielone na odrębne tożsamości. Dzięki temu Linuks izoluje aplikacje od siebie nawzajem i od systemu.

Aplikacje mogą udostępniać swoje funkcje innym aplikacjom, definiując uprawnienia, o które mogą poprosić 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 jest przechowywany przez dewelopera. Certyfikat nie musi być podpisany przez urząd certyfikacji. Aplikacje na Androida mogą używać certyfikatów podpisanych samodzielnie. Jest to dozwolone i typowe. Certyfikaty na Androidzie służą do rozróżniania autorów aplikacji. Dzięki temu system może przyznawać lub odmówić dostępu aplikacjom do uprawnień na poziomie podpisu oraz przyznawać lub odmówić aplikacji prośby o przyznanie tej samej tożsamości Linuxa co inna aplikacja.

Przyznawanie uprawnień do podpisu po wyprodukowaniu urządzenia

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

Możesz zadeklarować atrybut knownCerts i użyć flagi knownSigner w atrybutach protectionLevel aplikacji w przypadku konkretnego uprawnienia na poziomie podpisu. Następnie system przyznaje to uprawnienie aplikacji, która je zażądała, jeśli podpisujący w jej linii podpisywania (w tym bieżący podpisujący) odpowiada jednemu z skrótów zadeklarowanych w aplikacji za pomocą atrybutu knownCerts.

Flaga knownSigner umożliwia urządzeniom i aplikacjom przyznawanie uprawnień do podpisywania innym aplikacjom bez konieczności ich podpisywania w momencie produkcji i wysyłki urządzenia.

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

Podczas instalacji Android przypisuje do każdego pakietu osobny identyfikator użytkownika w systemie Linux. Tożsamość pozostaje niezmienna przez cały czas istnienia pakietu na danym urządzeniu. Na innym urządzeniu ten sam pakiet może mieć inny identyfikator UID – ważne jest, aby każdy pakiet miał unikalny identyfikator UID na danym urządzeniu.

Ponieważ egzekwowanie zabezpieczeń odbywa się na poziomie procesu, kod dowolnych 2 pakietów nie może być zwykle wykonywany w tym samym procesie, ponieważ muszą być wykonywane jako różne konta użytkowników systemu Linux.

Wszystkie dane przechowywane przez aplikację są przypisywane do identyfikatora użytkownika tej aplikacji i zwykle nie są dostępne dla innych pakietów.

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

Definiowanie i egzekwowanie uprawnień

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

Konwencja nazewnictwa

System nie zezwala na to, aby wiele pakietów deklarowało uprawnienie o tej samej nazwie, chyba że wszystkie pakiety są podpisane tym samym certyfikatem. Jeśli pakiet deklaruje uprawnienie, system nie zezwala użytkownikowi na instalowanie innych pakietów z tą samą nazwą uprawnienia, chyba że są one podpisane tym samym certyfikatem co pierwszy pakiet.

Zalecamy umieszczanie przed uprawnieniami nazwy pakietu aplikacji w odwrotnym stylu nazewnictwa domen, a następnie znaku .permission. i opisu możliwości, którą reprezentuje uprawnienie, w wielkim nazewnictwie SNAKE_CASE. Na przykład: com.example.myapp.permission.ENGAGE_HYPERSPACE.

Dzięki temu unikniesz kolizji nazw i możesz wyraźnie określić właściciela oraz cel uprawnienia niestandardowego.

Przykład

Na przykład aplikacja, która musi kontrolować, które inne aplikacje mogą uruchamiać jedną z jej aktywności, może zadeklarować uprawnienie 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 informować użytkowników o aplikacji wymagającej uprawnienia lub jakie aplikacje mogą mieć to uprawnienie, zgodnie z opisem w linkowanej dokumentacji.

Atrybut android:permissionGroup jest opcjonalny i służy tylko do wyświetlania uprawnień użytkownikowi. W większości przypadków ustawiasz tu standardową grupę systemową (wymienioną w sekcji android.Manifest.permission_group), chociaż możesz też zdefiniować grupę samodzielnie, jak opisano w następnej sekcji. Zalecamy użycie istniejącej grupy, ponieważ upraszcza to wyświetlany użytkownikowi interfejs uprawnień.

Musisz podać etykietę i opis uprawnienia. To zasoby znaków, które użytkownik może zobaczyć, gdy wyświetla listę uprawnień (android:label) lub szczegóły dotyczące pojedynczego uprawnienia (android:description). Etykieta jest krótka: to kilka słów opisujących główną funkcję, którą chroni uprawnienie. Opis składa się z kilku zdań opisujących, co uprawnienie pozwala zrobić. Zgodnie z naszą konwencją opis składa się z 2 zdań: pierwsze opisuje uprawnienie, a drugie ostrzega użytkownika przed tym, co może pójść nie tak, jeśli aplikacja uzyska 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>

Tworzenie grupy uprawnień

Jak pokazano w poprzedniej sekcji, możesz użyć atrybutu android:permissionGroup, aby ułatwić systemowi opisywanie uprawnień użytkownikowi. W większości przypadków ustawiasz tu standardową grupę systemową (wymienioną w sekcji android.Manifest.permission_group), ale możesz też zdefiniować własną grupę za pomocą parametru <permission-group>.

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

Możesz umieścić uprawnienie w grupie, przypisując nazwę grupy do atrybutu <permission>elementupermissionGroup.

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

Zalecane uprawnienia

Możesz definiować niestandardowe uprawnienia dla swoich aplikacji i prosić o niestandardowe uprawnienia z innych aplikacji, definiując elementy <uses-permission>. Należy jednak dokładnie rozważyć, czy jest to konieczne.

  • Jeśli opracowujesz pakiet aplikacji, które udostępniają sobie nawzajem funkcje, postaraj się zaprojektować je tak, aby każde uprawnienie było zdefiniowane tylko raz. Musisz to zrobić, jeśli nie wszystkie aplikacje są podpisane tym samym certyfikatem. Nawet jeśli wszystkie aplikacje są podpisane tym samym certyfikatem, zalecamy zdefiniowanie każdego uprawnienia tylko raz.
  • Jeśli funkcja jest dostępna tylko dla aplikacji podpisanych tym samym podpisem co aplikacja dostarczająca, możesz uniknąć definiowania niestandardowych uprawnień, korzystając z sprawdzeń podpisu. Gdy jedna z Twoich aplikacji wysyła żądanie do innej, ta druga może sprawdzić, czy obie są podpisane tym samym certyfikatem, zanim spełnią żądanie.

Jeśli potrzebne jest uprawnienie niestandardowe, zastanów się, czy dostęp do niego powinny mieć tylko aplikacje podpisane przez tego samego dewelopera, co aplikacja wykonująca sprawdzanie uprawnień. Może to być konieczne na przykład podczas implementowania bezpiecznej komunikacji między procesami w przypadku 2 aplikacji tego samego dewelopera. Jeśli tak, zalecamy użycie uprawnień podpisywania. Uprawnienia podpisu są przejrzyste dla użytkownika i unikają potwierdzania uprawnień przez użytkownika, co może być dla niego mylące.

Więcej informacji o:

<uses-permission>
Informacje o interfejsie API dla tagu manifestu, który deklaruje wymagane uprawnienia systemowe aplikacji.

Może Cię też zainteresować:

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