Funkcja Ustawienia bezpieczeństwa sieci umożliwia dostosowywanie ustawień bezpieczeństwa sieci aplikacji w bezpiecznym, deklaratywnym pliku konfiguracyjnym bez modyfikowania kodu aplikacji. Te ustawienia można skonfigurować dla określonych domen i konkretnej aplikacji. Najważniejsze funkcje tej funkcji to:
- Niestandardowe kotwice zaufania: dostosuj, które urzędy certyfikacji są zaufane w przypadku bezpiecznych połączeń aplikacji. Możesz na przykład zaufać konkretnym certyfikatom podpisanym samodzielnie lub ograniczyć zestaw publicznych urzędów certyfikacji, którym ufa aplikacja.
- Zastąpienia tylko na potrzeby debugowania: bezpieczne debugowanie zabezpieczonych połączeń w aplikacji bez dodatkowego ryzyka dla zainstalowanej bazy.
- Rezygnacja z ruchu w formie zwykłego tekstu: chroni aplikacje przed przypadkowym użyciem ruchu w formie zwykłego tekstu (niezaszyfrowanego).
- Włączenie projektu Certificate Transparency: ograniczenie bezpiecznych połączeń aplikacji do certyfikatów, które zostały zarejestrowane w sposób umożliwiający weryfikację.
- Przypinanie certyfikatów: ograniczanie bezpiecznego połączenia aplikacji do określonych certyfikatów.
Dodawanie pliku konfiguracji zabezpieczeń sieci
Funkcja Ustawienia bezpieczeństwa sieci korzysta z pliku XML, w którym określasz ustawienia aplikacji. Musisz dodać w pliku manifestu aplikacji wpis wskazujący ten plik. Poniższy fragment kodu z pliku manifestu pokazuje, jak utworzyć ten wpis:
<?xml version="1.0" encoding="utf-8"?> <manifest ... > <application android:networkSecurityConfig="@xml/network_security_config" ... > ... </application> </manifest>
Dostosowywanie zaufanych urzędów certyfikacji
Może się zdarzyć, że aplikacja ma ufać niestandardowemu zestawowi urzędów certyfikacji zamiast domyślnemu zestawowi platformy. Najczęstsze przyczyny to:
- łączenie się z hostem z niestandardowym urzędem certyfikacji, np. z urzędem certyfikacji podpisanym samodzielnie lub wydanym wewnętrznie w firmie;
- Ograniczenie zestawu urzędów certyfikacji do tych, którym ufasz, zamiast wszystkich preinstalowanych urzędów certyfikacji.
- ufać dodatkowym urzędom certyfikacji, które nie są uwzględnione w systemie;
Domyślnie bezpieczne połączenia (przy użyciu protokołów takich jak TLS i HTTPS) ze wszystkich aplikacji ufają preinstalowanym certyfikatom CA systemu, a aplikacje kierowane na Androida 6.0 (API na poziomie 23) i starsze domyślnie ufają też dodanemu przez użytkownika magazynowi certyfikatów CA. Połączenia aplikacji możesz dostosować za pomocą base-config
(w przypadku dostosowywania w całej aplikacji) lub domain-config
(w przypadku dostosowywania w poszczególnych domenach).
Konfigurowanie niestandardowego urzędu certyfikacji
Możesz chcieć połączyć się z hostem, który używa samodzielnie podpisanego certyfikatu SSL, lub z hostem, którego certyfikat SSL został wydany przez niepubliczny urząd certyfikacji, któremu ufasz, np. wewnętrzny urząd certyfikacji Twojej firmy.
Poniższy fragment kodu pokazuje, jak skonfigurować aplikację pod kątem niestandardowego urzędu certyfikacji w res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> </domain-config> </network-security-config>
Dodaj certyfikat CA podpisany samodzielnie lub niepubliczny w formacie PEM lub DER do res/raw/my_ca
.
Ograniczanie zestawu zaufanych urzędów certyfikacji
Jeśli nie chcesz, aby Twoja aplikacja ufała wszystkim urzędom certyfikacji, którym ufa system, możesz zamiast tego określić mniejszy zestaw urzędów certyfikacji, którym ma ufać aplikacja. Chroni to aplikację przed fałszywymi certyfikatami wydanymi przez inne urzędy certyfikacji.
Konfiguracja ograniczająca zestaw zaufanych certyfikatów CA jest podobna do zaufania niestandardowemu certyfikatowi CA w przypadku konkretnej domeny, z tym wyjątkiem, że w zasobie podanych jest wiele certyfikatów CA.
Poniższy fragment kodu pokazuje, jak ograniczyć zestaw zaufanych urzędów certyfikacji w aplikacji w res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">secure.example.com</domain> <domain includeSubdomains="true">cdn.example.com</domain> <trust-anchors> <certificates src="@raw/trusted_roots"/> </trust-anchors> </domain-config> </network-security-config>
Dodaj zaufane urzędy certyfikacji w formacie PEM lub DER do res/raw/trusted_roots
.
Pamiętaj, że jeśli używasz formatu PEM, plik musi zawierać tylko dane w tym formacie i żaden dodatkowy tekst. Zamiast jednego możesz podać kilka elementów <certificates>
.
Zaufanie dodatkowym urzędom certyfikacji
Możesz chcieć, aby Twoja aplikacja ufała dodatkowym urzędom certyfikacji, które nie są zaufane przez system, np. jeśli system jeszcze nie zawiera danego urzędu certyfikacji lub nie spełnia on wymagań dotyczących uwzględnienia w systemie Android. Możesz określić wiele źródeł certyfikatów dla konfiguracji w res/xml/network_security_config.xml
, używając kodu podobnego do poniższego fragmentu.
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <trust-anchors> <certificates src="@raw/extracas"/> <certificates src="system"/> </trust-anchors> </base-config> </network-security-config>
Konfigurowanie urzędów certyfikacji na potrzeby debugowania
Podczas debugowania aplikacji, która łączy się przez HTTPS, możesz chcieć połączyć się z lokalnym serwerem deweloperskim, który nie ma certyfikatu SSL serwera produkcyjnego. Aby to umożliwić bez modyfikowania kodu aplikacji, możesz określić urzędy certyfikacji tylko do debugowania, które są zaufane tylko wtedy, gdy android:debuggable ma wartość true
. W tym celu użyj debug-overrides
. Zwykle środowiska IDE i narzędzia do kompilacji automatycznie ustawiają tę flagę w przypadku wersji innych niż produkcyjne.
Jest to bezpieczniejsze niż zwykły kod warunkowy, ponieważ ze względów bezpieczeństwa sklepy z aplikacjami nie akceptują aplikacji, które są oznaczone jako możliwe do debugowania.
Fragment poniżej pokazuje, jak określić urzędy certyfikacji tylko do debugowania w res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <debug-overrides> <trust-anchors> <certificates src="@raw/debug_cas"/> </trust-anchors> </debug-overrides> </network-security-config>
Włączanie przejrzystości certyfikatów
Uwaga: obsługa przejrzystości certyfikatów jest dostępna tylko w Androidzie 16 (poziom API 36).
Certificate Transparency (CT, RFC 6962) to standard internetowy zaprojektowany w celu zwiększenia bezpieczeństwa certyfikatów cyfrowych. Wymaga on od urzędów certyfikacji przesyłania wszystkich wystawionych certyfikatów do publicznego dziennika, który je rejestruje, co zwiększa przejrzystość i odpowiedzialność w procesie wydawania certyfikatów.
Dzięki prowadzeniu weryfikowalnej ewidencji wszystkich certyfikatów CT znacznie utrudnia złośliwym podmiotom fałszowanie certyfikatów, a urzędom certyfikacji – ich przypadkowe wydawanie. Pomaga to chronić użytkowników przed atakami typu „man-in-the-middle” i innymi zagrożeniami związanymi z bezpieczeństwem. Więcej informacji znajdziesz w wyjaśnieniu na stronie transparency.dev. Więcej informacji o zgodności z CT na Androidzie znajdziesz w zasadach CT na Androidzie.
Domyślnie certyfikaty są akceptowane niezależnie od tego, czy są zapisane w dzienniku CT. Aby mieć pewność, że Twoja aplikacja łączy się tylko z miejscami docelowymi z certyfikatami zarejestrowanymi w logu CT, możesz włączyć tę funkcję globalnie lub dla poszczególnych domen.
Ruch w formie tekstu nieszyfrowanego
Deweloperzy mogą włączać lub wyłączać ruch w formie zwykłego tekstu (używając niezaszyfrowanego protokołu HTTP zamiast HTTPS) w swoich aplikacjach.
Więcej informacji znajdziesz w sekcji NetworkSecurityPolicy.isCleartextTrafficPermitted()
.
Domyślne zachowanie ruchu w postaci zwykłego tekstu zależy od poziomu interfejsu API:
- Do Androida 8.1 (poziom API 27) obsługa tekstu jawnego jest domyślnie włączona. Aplikacje mogą zrezygnować z przesyłania danych w formie niezaszyfrowanej, aby zwiększyć bezpieczeństwo.
- Od Androida 9 (poziom API 28) obsługa tekstu jawnego jest domyślnie wyłączona. Aplikacje, które wymagają ruchu nieszyfrowanego, mogą wyrazić zgodę na ruch nieszyfrowany.
Rezygnacja z ruchu w formie zwykłego tekstu
Uwaga: wskazówki w tej sekcji dotyczą tylko aplikacji przeznaczonych na Androida 8.1 (interfejs API na poziomie 27) lub starszego.
Jeśli chcesz, aby Twoja aplikacja łączyła się z miejscami docelowymi tylko za pomocą bezpiecznych połączeń, możesz zrezygnować z obsługi ruchu nieszyfrowanego do tych miejsc docelowych. Ta opcja pomaga zapobiegać przypadkowym regresjom w aplikacjach spowodowanym zmianami adresów URL dostarczanych przez zewnętrzne źródła, takie jak serwery backendu.
Możesz na przykład chcieć, aby aplikacja zapewniała, że połączenia z secure.example.com
są zawsze nawiązywane przez HTTPS, aby chronić wrażliwy ruch przed wrogimi sieciami.
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">secure.example.com</domain> </domain-config> </network-security-config>
Włączanie ruchu w formie zwykłego tekstu
Uwaga: wskazówki w tej sekcji dotyczą tylko aplikacji kierowanych na Androida 9 (API na poziomie 28) lub nowszego.
Jeśli aplikacja musi łączyć się z miejscami docelowymi za pomocą ruchu w postaci zwykłego tekstu (HTTP), możesz włączyć obsługę zwykłego tekstu w przypadku tych miejsc docelowych.
Możesz na przykład zezwolić aplikacji na nawiązywanie niezabezpieczonych połączeń z insecure.example.com
.
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">insecure.example.com</domain> </domain-config> </network-security-config>
Jeśli Twoja aplikacja musi wyrazić zgodę na ruch nieszyfrowany w dowolnej domenie, ustaw wartość
cleartextTrafficPermitted="true"
w base-config
.
Pamiętaj, że tej niebezpiecznej konfiguracji należy unikać, gdy tylko jest to możliwe.
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"> </base-config> </network-security-config>
Przypinanie certyfikatów
Zazwyczaj aplikacja ufa wszystkim wstępnie zainstalowanym urzędom certyfikacji. Jeśli któryś z tych urzędów certyfikacji wydałby fałszywy certyfikat, aplikacja byłaby narażona na atak typu „man-in-the-middle”. Niektóre aplikacje ograniczają zestaw akceptowanych certyfikatów, ograniczając zestaw zaufanych urzędów certyfikacji lub stosując przypinanie certyfikatów.
Przypinanie certyfikatów odbywa się przez podanie zestawu certyfikatów według skrótu klucza publicznego (SubjectPublicKeyInfo
certyfikatu X.509). Łańcuch certyfikatów jest wtedy ważny tylko wtedy, gdy zawiera co najmniej jeden przypięty klucz publiczny.
Pamiętaj, że podczas korzystania z przypinania certyfikatów zawsze należy uwzględniać klucz zapasowy. Dzięki temu, jeśli będziesz zmuszony(-a) do przejścia na nowe klucze lub zmiany urzędów certyfikacji (w przypadku przypinania do certyfikatu urzędu certyfikacji lub pośredniego urzędu certyfikacji), nie wpłynie to na łączność aplikacji. W przeciwnym razie musisz wdrożyć aktualizację aplikacji, aby przywrócić łączność.
Można też ustawić czas wygaśnięcia przypięć, po którym przypinanie nie będzie wykonywane. Pomaga to zapobiegać problemom z łącznością w aplikacjach, które nie zostały zaktualizowane. Ustawienie czasu wygaśnięcia przypiętych certyfikatów może jednak umożliwić hakerom ich obejście.
Poniższy fragment pokazuje, jak przypiąć certyfikaty w res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <pin-set expiration="2018-01-01"> <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> <!-- backup pin --> <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin> </pin-set> </domain-config> </network-security-config>
Dziedziczenie konfiguracji
Wartości, które nie zostały ustawione w konkretnej konfiguracji, są dziedziczone. Takie działanie umożliwia bardziej złożone konfiguracje przy zachowaniu czytelności pliku konfiguracyjnego.
Na przykład wartości nieustawione w elemencie domain-config
są pobierane z elementu nadrzędnego domain-config
, jeśli jest zagnieżdżony, lub z elementu base-config
, jeśli nie jest zagnieżdżony. Wartości nieustawione w base-config
korzystają z wartości domyślnych platformy.
Rozważmy na przykład sytuację, w której wszystkie połączenia z subdomenami domeny example.com
muszą korzystać z niestandardowego zestawu urzędów certyfikacji. Dodatkowo ruch nieszyfrowany do tych domen jest dozwolony z wyjątkiem połączeń z secure.example.com
.
Zagnieżdżając konfigurację secure.example.com
w konfiguracji example.com
, nie musisz duplikować trust-anchors
.
Poniższy fragment pokazuje, jak wyglądałoby to zagnieżdżenie w res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">secure.example.com</domain> </domain-config> </domain-config> </network-security-config>
Format pliku konfiguracji
Funkcja konfiguracji bezpieczeństwa sieci korzysta z formatu pliku XML. Ogólną strukturę pliku przedstawia ten przykładowy kod:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <trust-anchors> <certificates src="..."/> ... </trust-anchors> </base-config> <domain-config> <domain>android.com</domain> ... <trust-anchors> <certificates src="..."/> ... </trust-anchors> <pin-set> <pin digest="...">...</pin> ... </pin-set> </domain-config> ... <debug-overrides> <trust-anchors> <certificates src="..."/> ... </trust-anchors> </debug-overrides> </network-security-config>
W sekcjach poniżej znajdziesz opis składni i innych szczegółów formatu pliku.
<network-security-config>
- Może zawierać:
-
0 lub 1 wystąpienie znaku
<base-config>
Dowolna liczba wystąpień znaku<domain-config>
0 lub 1 wystąpienie znaku<debug-overrides>
<base-config>
- składnia:
<base-config cleartextTrafficPermitted=["true" | "false"]> ... </base-config>
- Może zawierać:
-
<trust-anchors>
<certificateTransparency>
- description:
-
Domyślna konfiguracja używana przez wszystkie połączenia, których miejsce docelowe nie jest objęte
domain-config
.Wszystkie wartości, które nie są ustawione, używają wartości domyślnych platformy.
Domyślna konfiguracja aplikacji kierowanych na Androida 9 (API na poziomie 28) lub nowszego jest następująca:
<base-config cleartextTrafficPermitted="false"> <trust-anchors> <certificates src="system" /> </trust-anchors> </base-config>
Domyślna konfiguracja aplikacji kierowanych na Androida 7.0 (poziom interfejsu API 24) do Androida 8.1 (poziom interfejsu API 27) jest następująca:
<base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates src="system" /> </trust-anchors> </base-config>
Domyślna konfiguracja aplikacji kierowanych na Androida 6.0 (poziom interfejsu API 23) i starszego jest następująca:
<base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates src="system" /> <certificates src="user" /> </trust-anchors> </base-config>
<domain-config>
- składnia:
-
<domain-config cleartextTrafficPermitted=["true" | "false"]> ... </domain-config>
- Może zawierać:
-
1 lub więcej
<domain>
0 lub 1<certificateTransparency>
0 lub 1<trust-anchors>
0 lub 1<pin-set>
Dowolna liczba zagnieżdżonych<domain-config>
- description:
- Konfiguracja używana w przypadku połączeń z określonymi miejscami docelowymi zdefiniowanymi przez elementy
domain
.Jeśli miejsce docelowe jest objęte kilkoma elementami
domain-config
, używana jest konfiguracja z najbardziej szczegółową (najdłuższą) pasującą regułą domeny.
<domena>
- składnia:
-
<domain includeSubdomains=["true" | "false"]>example.com</domain>
- atrybuty:
-
-
includeSubdomains
-
Jeśli
"true"
, ta reguła domeny pasuje do domeny i wszystkich subdomen, w tym subdomen subdomen. W przeciwnym razie reguła ma zastosowanie tylko do dopasowań ścisłych.
-
<certificateTransparency>
- składnia:
-
<certificateTransparency enabled=["true" | "false"]/>
- description:
-
Jeśli
true
, aplikacja będzie używać dzienników przejrzystości certyfikatów do weryfikowania certyfikatów. Jeśli aplikacja używa własnego certyfikatu (lub magazynu użytkownika), prawdopodobnie certyfikat nie jest publiczny, a tym samym nie można go zweryfikować za pomocą przejrzystości certyfikatów. Domyślnie weryfikacja jest w tych przypadkach wyłączona. W konfiguracji domeny nadal można wymusić weryfikację za pomocą<certificateTransparency enabled="true"/>
. W przypadku każdego<domain-config>
ocena jest przeprowadzana w tej kolejności:- Jeśli
certificateTransparency
jest włączona, włącz weryfikację. -
Jeśli którykolwiek z elementów
<trust-anchors>
jest"user"
lub wstawiony (tzn."@raw/cert.pem"
), wyłącz weryfikację. - W przeciwnym razie skorzystaj z dziedziczonej konfiguracji.
- Jeśli
<debug-overrides>
- składnia:
-
<debug-overrides> ... </debug-overrides>
- Może zawierać:
-
0 lub 1
<trust-anchors>
- description:
-
Zastąpienia, które mają być stosowane, gdy android:debuggable
ma wartość
"true"
, co zwykle ma miejsce w przypadku wersji innych niż wersje do publikacji generowanych przez środowiska IDE i narzędzia do kompilacji. Kotwice zaufania określone wdebug-overrides
są dodawane do wszystkich innych konfiguracji, a przypinanie certyfikatów nie jest wykonywane, gdy łańcuch certyfikatów serwera używa jednej z tych kotwic zaufania przeznaczonych tylko do debugowania. Jeśli android:debuggable ma wartość"false"
, ta sekcja jest całkowicie ignorowana.
<trust-anchors>
- składnia:
-
<trust-anchors> ... </trust-anchors>
- Może zawierać:
-
Dowolna liczba znaków
<certificates>
- description:
- Zestaw zaufanych punktów zakotwiczenia dla bezpiecznych połączeń.
<certificates>
- składnia:
<certificates src=["system" | "user" | "raw resource"] overridePins=["true" | "false"] />
- description:
- Zestaw certyfikatów X.509 dla elementów
trust-anchors
. - atrybuty:
-
src
-
Źródło certyfikatów CA. Każdy certyfikat może mieć jedną z tych wartości:
- surowy identyfikator zasobu wskazujący plik zawierający certyfikaty X.509. Certyfikaty muszą być zakodowane w formacie DER lub PEM. W przypadku certyfikatów PEM plik nie może zawierać dodatkowych danych innych niż PEM, takich jak komentarze.
"system"
w przypadku fabrycznie zainstalowanych systemowych certyfikatów CA."user"
w przypadku certyfikatów CA dodanych przez użytkowników;
overridePins
-
Określa, czy urzędy certyfikacji z tego źródła pomijają przypinanie certyfikatów. Jeśli
"true"
, to przypinanie nie jest wykonywane w przypadku łańcuchów certyfikatów podpisanych przez jeden z urzędów certyfikacji z tego źródła. Może to być przydatne podczas debugowania urzędów certyfikacji lub testowania ataków typu „man in the middle” na bezpieczny ruch aplikacji.Wartość domyślna to
"false"
, chyba że w elemenciedebug-overrides
określono inną wartość. W takim przypadku wartość domyślna to"true"
.
<pin-set>
- składnia:
-
<pin-set expiration="date"> ... </pin-set>
- Może zawierać:
-
Dowolna liczba znaków
<pin>
- description:
-
Zbiór przypiętych kluczy publicznych. Aby bezpieczne połączenie było zaufane, jeden z kluczy publicznych w łańcuchu zaufania musi znajdować się w zestawie przypiętych kluczy. Informacje o formacie pinezek znajdziesz na stronie
<pin>
. - atrybuty:
-
-
expiration
-
Data wygaśnięcia przypięć w formacie
yyyy-MM-dd
, która powoduje wyłączenie przypinania. Jeśli atrybut nie jest ustawiony, kody PIN nie wygasają.Wygasanie pomaga zapobiegać problemom z łącznością w aplikacjach, które nie otrzymują aktualizacji zestawu pinów, np. gdy użytkownik wyłączy aktualizacje aplikacji.
-
<pin>
- składnia:
-
<pin digest=["SHA-256"]>base64 encoded digest of X.509 SubjectPublicKeyInfo (SPKI)</pin>
- atrybuty:
-
-
digest
- Algorytm skrótu użyty do wygenerowania kodu PIN. Obecnie obsługiwana jest tylko forma
"SHA-256"
.
-