Konfiguracja zabezpieczeń sieci

Funkcja konfiguracji zabezpieczeń sieci umożliwia dostosowanie ustawień zabezpieczeń sieci aplikacji w bezpiecznym, deklaratywnym pliku konfiguracyjnym bez konieczności modyfikowania kodu aplikacji. Te ustawienia można skonfigurować w przypadku określonych domen i aplikacji. Najważniejsze możliwości tej funkcji to:

  • Niestandardowe punkty zaufania: możesz wybrać, które urzędy certyfikacji (CA) mają być zaufane w przypadku bezpiecznych połączeń aplikacji. Na przykład można ufać określonym samopodpisanym certyfikatom lub ograniczyć zestaw zaufanych urzędów certyfikacji.
  • Zastąpienia tylko na potrzeby debugowania: bezpieczne debugowanie połączeń zabezpieczonych w aplikacji bez zwiększonego ryzyka dla zainstalowanej bazy.
  • Wyłączenie ruchu w pełnym tekście: chroni aplikacje przed przypadkowym użyciem ruchu w pełnym tekście (niezaszyfrowanym).
  • Uzyskiwanie dostępu do certyfikatu: ogranicza bezpieczne połączenia aplikacji do korzystania z certyfikatów z potwierdzonym logowaniem.
  • Przypinanie certyfikatu: ogranicza bezpieczne połączenie aplikacji do określonych certyfikatów.

Dodawanie pliku konfiguracji zabezpieczeń sieci

Funkcja konfiguracji zabezpieczeń sieci korzysta z pliku XML, w którym określasz ustawienia aplikacji. Musisz uwzględnić wpis w pliku manifestu aplikacji, aby wskazać ten plik. Poniżej znajdziesz fragment kodu z pliku manifestu, który 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żesz chcieć, aby Twoja aplikacja ufała niestandardowemu zestawowi urzędów certyfikacji zamiast domyślnemu zestawowi urzędów certyfikacji platformy. Najczęstsze przyczyny to:

  • połączenie z hostem za pomocą urzędu certyfikacji niestandardowego, takiego jak urząd certyfikacji podpisany samodzielnie lub wydany wewnętrznie w firmie;
  • Ograniczenie zestawu urzędów certyfikacji do tych, którym ufasz, zamiast do wszystkich wstępnie zainstalowanych urzędów certyfikacji.
  • zaufanie do dodatkowych urzędów certyfikacji, które nie są uwzględnione w systemie;

Domyślnie bezpieczne połączenia (wykorzystujące protokoły takie jak TLS i HTTPS) ze wszystkich aplikacji korzystają z zainstalowanych fabrycznie urzędów certyfikacji, a aplikacje kierowane na Androida 6.0 (poziom interfejsu API 23) i starsze domyślnie ufają również magazynowi urzędów certyfikacji dodanych przez użytkownika. Połączenia aplikacji możesz dostosować za pomocą base-config (w przypadku dostosowywania na poziomie całej aplikacji) lub domain-config (w przypadku dostosowywania na poziomie domeny).

Konfigurowanie niestandardowego urzędu certyfikacji

Możesz nawiązać połączenie 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. Ten fragment kodu pokazuje, jak skonfigurować aplikację pod kątem certyfikatu CA niestandardowego w pliku 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 podpisany samodzielnie lub niepubliczny certyfikat urzędu certyfikacji w formacie PEM lub DER do res/raw/my_ca.

Ogranicz zestaw zaufanych urzędów certyfikacji

Jeśli nie chcesz, aby Twoja aplikacja ufała wszystkim zaufanym urzędom certyfikacji, możesz zamiast tego określić mniejszy zestaw zaufanych urzędów certyfikacji. Dzięki temu aplikacja jest chroniona przed fałszywymi certyfikatami wydanymi przez inne urzędy certyfikacji.

Konfiguracja służąca do ograniczenia zestawu zaufanych urzędów certyfikacji jest podobna do ufania niestandardowemu urzędowi certyfikacji w przypadku konkretnej domeny, z tą różnicą, że w zasobie podano wiele urzędów certyfikacji. Ten fragment kodu pokazuje, jak ograniczyć zestaw zaufanych urzędów certyfikacji 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 PEM i nie może zawierać dodatkowego tekstu. Możesz też podać więcej niż 1 <certificates>.

Uwierzytelniaj dodatkowe urzędy certyfikacji

Możesz chcieć, aby Twoja aplikacja ufała dodatkowym urzędom certyfikacji, które nie są zaufane przez system, na przykład jeśli system nie zawiera jeszcze urzędu certyfikacji lub urząd certyfikacji nie spełnia wymagań dotyczących włączenia do systemu Android. W konfiguracji res/xml/network_security_config.xml możesz określić wiele źródeł certyfikatów, używając kodu podobnego do tego:

<?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 połączyć się z lokalnym serwerem deweloperskim, który nie ma certyfikatu SSL dla serwera produkcyjnego. Aby umożliwić to bez wprowadzania zmian w kodzie aplikacji, możesz określić urzędy certyfikacji służące tylko do debugowania, które są zaufane tylko wtedy, gdy atrybut android:debuggable ma wartość true. W tym celu użyj elementu debug-overrides. Zwykle IDE i narzędzia do kompilacji automatycznie ustawiają ten parametr w przypadku kompilacji nie przeznaczonych do wydania.

Jest to bezpieczniejsze niż zwykły kod warunkowy, ponieważ w ramach środków ostrożności sklepy z aplikacjami nie akceptują aplikacji oznaczonych jako debugowane.

Fragment poniżej pokazuje, jak w res/xml/network_security_config.xml określić urzędy certyfikacji przeznaczone tylko do debugowania:

<?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

Transparentność certyfikatów (CT, RFC 9162) to standard internetowy mający na celu zwiększenie bezpieczeństwa certyfikatów cyfrowych. Wymaga ona, aby urzędy certyfikacji przesyłały wszystkie wystawione certyfikaty do publicznego dziennika, co zwiększa przejrzystość i odpowiedzialnie w procesie wystawiania certyfikatów.

Dzięki utrzymywaniu weryfikowalnej listy wszystkich certyfikatów CT znacznie utrudnia złośliwym podmiotom fałszowanie certyfikatów lub urzędom certyfikacji przypadkowe ich wydawanie. Pomaga to chronić użytkowników przed atakami typu „man in the middle” i innymi zagrożeniami dla bezpieczeństwa. Więcej informacji znajdziesz w artykule transparency.dev.

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, których certyfikaty są rejestrowane w logu CT, możesz włączyć tę funkcję globalnie lub w przypadku poszczególnych domen.

Rezygnacja z ruchu w formie zwykłego tekstu

Uwaga: wskazówki w tej sekcji dotyczą tylko aplikacji kierowanych na Androida 8.1 (poziom interfejsu API 27) lub niższego. Od wersji 9 Androida (poziom interfejsu API 28) obsługa tekstów zwykłych jest domyślnie wyłączona.

Jeśli chcesz, aby Twoja aplikacja łączyła się z miejscami docelowymi tylko za pomocą bezpiecznych połączeń, możesz zrezygnować z obsługi tekstów zwykłych (za pomocą niezaszyfrowanego protokołu HTTP zamiast HTTPS). Ta opcja pomaga zapobiegać przypadkowym regresjom w aplikacjach z powodu zmian adresów URL udostępnianych przez źródła zewnętrzne, takie jak serwery zaplecza. Więcej informacji znajdziesz w artykule NetworkSecurityPolicy.isCleartextTrafficPermitted().

Możesz na przykład chcieć, aby aplikacja zawsze nawiązywała połączenia z secure.example.comza pomocą protokołu HTTPS, aby chronić wrażliwy ruch przed nieprzyjaznymi sieciami.

Z poniższego fragmentu dowiesz się, jak zrezygnować z wyświetlania tekstu w res/xml/network_security_config.xml:

<?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>

Przypinanie certyfikatów

Zwykle aplikacja ufa wszystkim zainstalowanym fabrycznie urzędom certyfikacji. Jeśli któryś z tych urzędów certyfikacji wyda fałszywy certyfikat, aplikacja będzie narażona na atak na drodze. Niektóre aplikacje ograniczają zestaw certyfikatów, które akceptują, ograniczając zestaw zaufanych urzędów certyfikacji lub przypinając certyfikat.

Przypinanie certyfikatów odbywa się poprzez podanie zestawu certyfikatów według hasha klucza publicznego (SubjectPublicKeyInfo certyfikatu X.509). Łańcuch certyfikatów jest ważny tylko wtedy, gdy zawiera co najmniej jeden z przypiętych kluczy publicznych.

Pamiętaj, że jeśli korzystasz z przypinania certyfikatu, zawsze musisz uwzględnić klucz zapasowy, aby w razie konieczności przejścia na nowe klucze lub zmiany urzędów certyfikacji (przypinania do certyfikatu urzędu certyfikacji lub pośredniego urzędu certyfikacji tego urzędu) nie wpływać na łączność aplikacji. W przeciwnym razie, aby przywrócić połączenie, musisz wdrożyć aktualizację aplikacji.

Dodatkowo można ustawić czas wygaśnięcia pinów, po którym nie są one już przypinane. Pomoże to uniknąć problemów z połączeniem w aplikacji, która nie została zaktualizowana. Ustawienie czasu ważności pinek może jednak umożliwić hakerom obejście pinekowanych certyfikatów.

Ten 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 określone w konkretnej konfiguracji, są dziedziczone. Dzięki temu możesz tworzyć bardziej złożone konfiguracje, zachowując czytelność pliku konfiguracyjnego.

Na przykład wartości, które nie są ustawione w elementach domain-config, są pobierane z elementu nadrzędnego domain-config (jeśli są zagnieżdżone) lub z elementu base-config (jeśli nie są zagnieżdżone). Wartości, które nie zostały określone w base-config, mają wartości domyślne platformy.

Rozważmy na przykład przypadek, w którym wszystkie połączenia z subdomenami example.com muszą używać niestandardowego zestawu urzędów certyfikacji. Dodatkowo ruch nieszyfrowany do tych domen jest dozwolony z wyjątkiem połączenia z adresem secure.example.com. Dzięki zagnieżdżeniu konfiguracji secure.example.com w konfiguracji example.com nie trzeba duplikować konfiguracji trust-anchors.

Poniżej możesz zobaczyć, jak wygląda to zagnieżdżenie w pliku 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 Ustawienia bezpieczeństwa sieci korzysta z formatu pliku XML. Ogólna struktura pliku jest pokazana w tym przykładowym kodzie:

<?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 następnych sekcjach opisujemy składnię i inne szczegóły formatu pliku.

<network-security-config>

może zawierać:
0 lub 1 wartości <base-config>
dowolna liczba wartości <domain-config>
0 lub 1 wartości <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 zasadą domain-config.

W przypadku wartości, które nie są ustawione, używane są wartości domyślne platformy.

Domyślna konfiguracja aplikacji kierowanych na Androida 9 (poziom API 28) lub nowszego:

<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) lub starszego:

<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 do połączeń z określonymi miejscami docelowymi, zgodnie z definicją elementów domain.

Pamiętaj, że jeśli miejsce docelowe jest objęte przez wiele elementów domain-config, używana jest konfiguracja z najbardziej szczegółową (najdłuższą) regułą dopasowywania domeny.

<domena>

składnia:
<domain includeSubdomains=["true" | "false"]>example.com</domain>
atrybuty:
includeSubdomains
Jeśli "true", to to reguła domeny pasuje do domeny i wszystkich subdomen, w tym do subdomen subdomen. W przeciwnym razie reguła będzie miała zastosowanie tylko do dopasowań ścisłych.

<certificateTransparency>

składnia:
<certificateTransparency enabled=["true" | "false"]/>
description:
Jeśli true, aplikacja będzie używać dzienników Certificate Transparency do sprawdzania certyfikatów. Gdy aplikacja używa własnego certyfikatu (lub magazynu użytkownika), prawdopodobnie certyfikat nie jest publiczny i nie można go zweryfikować za pomocą przejrzystości certyfikatu. Domyślnie weryfikacja jest w takich przypadkach wyłączona. Nadal można wymusić weryfikację za pomocą parametru <certificateTransparency enabled="true"/> w konfiguracji domeny. W przypadku każdego <domain-config> ocena jest przeprowadzana w tej kolejności:
  1. Jeśli certificateTransparency jest włączona, włącz weryfikację.
  2. Jeśli <trust-anchors> jest "user" lub wstawiane w tekście (tzn. "@raw/cert.pem"), wyłącz weryfikację.
  3. W przeciwnym razie użyj odziedowanej konfiguracji.

<debug-overrides>

składnia:
<debug-overrides>
    ...
</debug-overrides>
może zawierać:
0 lub 1 <trust-anchors>
description:
Zmienniki, które mają być stosowane, gdy android:debuggable ma wartość "true", co jest zwykle przypadkiem wersji niewydawanych wygenerowanych przez IDE i narzędzia do kompilacji. Kotwicy zaufania określone w debug-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 to "false", ta sekcja jest całkowicie ignorowana.

<trust-anchors>

składnia:
<trust-anchors>
...
</trust-anchors>
może zawierać:
dowolna liczba wartości <certificates>
description:
Zestaw punktów zaufania na potrzeby bezpiecznych połączeń.

<certificates>

składnia:
<certificates src=["system" | "user" | "raw resource"]
              overridePins=["true" | "false"] />
description:
Zbiór certyfikatów X.509 dla elementów trust-anchors.
atrybuty:
src
Źródło certyfikatów CA. Każdy certyfikat może być jednym z tych elementów:
  • identyfikator zasobu nieprzetworzonego wskazującego na 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 wstępnie zainstalowanych certyfikatów CA systemu
  • "user" w przypadku certyfikatów CA dodanych przez użytkownika.
overridePins

Określa, czy urzędy certyfikacji z tego źródła pomijają przypinanie certyfikatu. Jeśli "true", nie jest wykonywane przypinanie łańcuchów certyfikatów, które są podpisane przez jeden z urzędów certyfikacji z tego źródła. Może to być przydatne podczas debugowania CA lub testowania ataków typu „man in the middle” na zabezpieczonym ruchu w aplikacji.

Wartość domyślna to "false", chyba że jest określona w elemencie debug-overrides. W takim przypadku wartość domyślna to "true".

<pin-set>

składnia:
<pin-set expiration="date">
...
</pin-set>
może zawierać:
dowolna liczba wartości <pin>
description:
Zbiór pinów klucza publicznego. Aby bezpieczne połączenie było zaufane, jeden z kluczy publicznych w łańcuchu zaufania musi znajdować się w zestawie pinów. Format pinów znajdziesz na stronie <pin>.
atrybuty:
expiration
data w formacie yyyy-MM-dd, w której pinezki tracą ważność, co powoduje wyłączenie przypinania. Jeśli atrybut nie jest ustawiony, piny nie wygasają.

Wygaśnięcie pomaga zapobiegać problemom z połączeniem w przypadku aplikacji, które nie otrzymują aktualizacji zestawu pinów, na przykład 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 pinu. Obecnie obsługiwana jest tylko forma "SHA-256".

Dodatkowe materiały

Więcej informacji o konfiguracji zabezpieczeń sieci znajdziesz w tych materiałach.

Ćwiczenia z programowania