Zwiększając bezpieczeństwo aplikacji, pomagasz zachować zaufanie użytkowników i integralność urządzenia.
Na tej stronie znajdziesz kilka sprawdzonych metod, które mają znaczący, pozytywny wpływ na bezpieczeństwo aplikacji.
Wymuszanie bezpiecznej komunikacji
Zabezpieczając dane wymieniane między Twoją aplikacją a innymi aplikacjami lub między Twoją aplikacją a witryną, zwiększasz stabilność aplikacji i chronisz wysyłane i odbierane dane.
Zabezpieczanie komunikacji między aplikacjami
Aby bezpieczniej komunikować się między aplikacjami, używaj intencji niejawnych z selektorem aplikacji, uprawnień opartych na podpisie i nieeksportowanych mechanizmów dostarczania treści.
Wyświetlanie selektora aplikacji
Jeśli intencja niejawna może uruchomić co najmniej 2 aplikacje na urządzeniu użytkownika, wyraźnie wyświetl selektor aplikacji. Ta strategia interakcji pozwala użytkownikom przesyłać informacje poufne do aplikacji, której ufają.
Kotlin
val intent = Intent(Intent.ACTION_SEND)
val possibleActivitiesList: List<ResolveInfo> =
packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)
// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size > 1) {
// Create intent to show chooser.
// Title is something similar to "Share this photo with."
<b>val chooser = resources.getString(R.string.chooser_title).let { title ->
Intent.createChooser(intent, title)
}
startActivity(chooser)</b>
} else if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
Java
Intent intent = new Intent(Intent.ACTION_SEND);
List<ResolveInfo> possibleActivitiesList = getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_ALL);
// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size() > 1) {
// Create intent to show chooser.
// Title is something similar to "Share this photo with."
<b>String title = getResources().getString(R.string.chooser_title);
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);</b>
} else if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
Powiązane informacje:
Stosowanie uprawnień opartych na podpisie
Podczas udostępniania danych między 2 aplikacjami, które kontrolujesz lub których jesteś właścicielem, używaj uprawnień opartych na podpisie. Te uprawnienia nie wymagają potwierdzenia przez użytkownika. Zamiast tego sprawdzają, czy aplikacje uzyskujące dostęp do danych są podpisane tym samym kluczem podpisywania. Dzięki temu te uprawnienia zapewniają użytkownikom większą wygodę i bezpieczeństwo.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <permission android:name="my_custom_permission_name" android:protectionLevel="signature" />
Powiązane informacje:
Blokowanie dostępu do mechanizmów dostarczania treści w aplikacji
Jeśli nie zamierzasz wysyłać danych z aplikacji do innej aplikacji, która nie należy do Ciebie, wyraźnie zablokuj aplikacjom innych deweloperów dostęp do obiektów ContentProvider Twojej aplikacji. To ustawienie jest szczególnie ważne, jeśli aplikację można zainstalować na urządzeniach z Androidem 4.1.1 (API na poziomie 16) lub starszym, ponieważ w tych wersjach Androida atrybut android:exported elementu <provider> ma domyślnie wartość true.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <application ... > <provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.myapp.fileprovider" ... android:exported="false"> <!-- Place child elements of <provider> here. --> </provider> ... </application> </manifest>
Pytaj o dane logowania przed wyświetleniem informacji poufnych
Gdy prosisz użytkowników o podanie danych uwierzytelniających, aby mogli uzyskać dostęp do informacji poufnych lub treści premium w aplikacji, poproś o kod PIN, hasło, wzór lub dane biometryczne, takie jak rozpoznawanie twarzy lub odcisku palca.
Więcej informacji o tym, jak poprosić o dane biometryczne, znajdziesz w przewodniku po uwierzytelnianiu biometrycznym.
Stosowanie środków bezpieczeństwa sieci
W sekcjach poniżej opisujemy, jak możesz poprawić bezpieczeństwo sieciowe aplikacji.
Używanie ruchu TLS
Jeśli Twoja aplikacja komunikuje się z serwerem internetowym, który ma certyfikat wydany przez znany, zaufany urząd certyfikacji, użyj żądania HTTPS takiego jak to:
Kotlin
val url = URL("https://www.google.com")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.connect()
urlConnection.inputStream.use {
...
}
Java
URL url = new URL("https://www.google.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
InputStream in = urlConnection.getInputStream();
Dodawanie konfiguracji zabezpieczeń sieci
Jeśli aplikacja używa nowych lub niestandardowych urzędów certyfikacji, możesz zadeklarować ustawienia zabezpieczeń sieci w pliku konfiguracji. Dzięki temu możesz utworzyć konfigurację bez modyfikowania kodu aplikacji.
Aby dodać do aplikacji plik konfiguracji zabezpieczeń sieci, wykonaj te czynności:
- Zadeklaruj konfigurację w pliku manifestu aplikacji:
-
Dodaj plik zasobów XML znajdujący się w
res/xml/network_security_config.xml.Określ, że cały ruch do określonych domen musi używać protokołu HTTPS, wyłączając zwykły tekst:
<network-security-config> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">secure.example.com</domain> ... </domain-config> </network-security-config>
Podczas procesu programowania możesz użyć elementu
<debug-overrides>, aby wyraźnie zezwolić na certyfikaty zainstalowane przez użytkownika. Ten element zastępuje opcje aplikacji o krytycznym znaczeniu dla bezpieczeństwa podczas debugowania i testowania bez wpływu na konfigurację wersji aplikacji. Poniższy fragment kodu pokazuje, jak zdefiniować ten element w pliku XML konfiguracji zabezpieczeń sieci aplikacji:<network-security-config> <debug-overrides> <trust-anchors> <certificates src="user" /> </trust-anchors> </debug-overrides> </network-security-config>
<manifest ... > <application android:networkSecurityConfig="@xml/network_security_config" ... > <!-- Place child elements of <application> element here. --> </application> </manifest>
Powiązane informacje: konfiguracja zabezpieczeń sieci
Tworzenie własnego menedżera zaufania
Narzędzie do sprawdzania TLS nie powinno akceptować każdego certyfikatu. Jeśli w Twoim przypadku zachodzi jedna z tych sytuacji, konieczne może być skonfigurowanie menedżera zaufania i obsługa wszystkich ostrzeżeń dotyczących protokołu TLS:
- Komunikujesz się z serwerem WWW, który ma certyfikat podpisany przez nowy lub niestandardowy urząd certyfikacji.
- Urządzenie, którego używasz, nie ufa temu urzędowi certyfikacji.
- Nie możesz używać konfiguracji zabezpieczeń sieci.
Więcej informacji o tym, jak wykonać te czynności, znajdziesz w artykule o nieznanym urzędzie certyfikacji.
Powiązane informacje:
Ostrożne używanie obiektów WebView
Obiekty WebView w aplikacji nie powinny umożliwiać użytkownikom przechodzenia do witryn, nad którymi nie masz kontroli. W miarę możliwości używaj listy dozwolonych, aby ograniczyć treści wczytywane przez obiekty WebView aplikacji.
Nie włączaj też obsługi interfejsu JavaScript, chyba że masz pełną kontrolę nad treściami w obiektach WebView aplikacji i w pełni im ufasz.
Używanie kanałów wiadomości HTML
Jeśli aplikacja musi korzystać z obsługi interfejsu JavaScript na urządzeniach z Androidem 6.0 (interfejs API na poziomie 23) lub nowszym, zamiast komunikacji między witryną a aplikacją użyj kanałów wiadomości HTML, jak pokazano w tym fragmencie kodu:
Kotlin
val myWebView: WebView = findViewById(R.id.webview)
// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
val channel: Array<out WebMessagePort> = myWebView.createWebMessageChannel()
// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() {
override fun onMessage(port: WebMessagePort, message: WebMessage) {
Log.d(TAG, "On port $port, received this message: $message")
}
})
// Send a message from channel[1] to channel[0].
channel[1].postMessage(WebMessage("My secure message"))
Java
WebView myWebView = (WebView) findViewById(R.id.webview);
// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
WebMessagePort[] channel = myWebView.createWebMessageChannel();
// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
@Override
public void onMessage(WebMessagePort port, WebMessage message) {
Log.d(TAG, "On port " + port + ", received this message: " + message);
}
});
// Send a message from channel[1] to channel[0].
channel[1].postMessage(new WebMessage("My secure message"));
Powiązane informacje:
Przyznawanie odpowiednich uprawnień
Aplikacja powinna prosić tylko o minimalną liczbę uprawnień niezbędnych do jej prawidłowego działania. Jeśli to możliwe, zrezygnuj z uprawnień, gdy aplikacja nie będzie ich już potrzebować.
Używanie intencji do odraczania uprawnień
Jeśli to możliwe, nie dodawaj do aplikacji uprawnień, aby wykonać działanie, które można wykonać w innej aplikacji. Zamiast tego użyj intencji, aby przekazać żądanie do innej aplikacji, która ma już wymagane uprawnienia.
Ten przykład pokazuje, jak użyć intencji, aby przekierować użytkowników do aplikacji do obsługi kontaktów, zamiast prosić o uprawnienia READ_CONTACTS i WRITE_CONTACTS:
Kotlin
// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent(Intent.ACTION_INSERT).apply {
type = ContactsContract.Contacts.CONTENT_TYPE
}.also { intent ->
// Make sure that the user has a contacts app installed on their device.
intent.resolveActivity(packageManager)?.run {
startActivity(intent)
}
}
Java
// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent insertContactIntent = new Intent(Intent.ACTION_INSERT);
insertContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);
// Make sure that the user has a contacts app installed on their device.
if (insertContactIntent.resolveActivity(getPackageManager()) != null) {
startActivity(insertContactIntent);
}
Jeśli aplikacja musi wykonywać operacje wejścia/wyjścia na plikach, np. uzyskiwać dostęp do pamięci lub wybierać plik, nie potrzebuje specjalnych uprawnień, ponieważ system może wykonywać te operacje w jej imieniu. Co więcej, gdy użytkownik wybierze treści pod określonym identyfikatorem URI, aplikacja do dzwonienia uzyska uprawnienia do wybranego zasobu.
Powiązane informacje:
Bezpieczne udostępnianie danych między aplikacjami
Postępuj zgodnie z tymi sprawdzonymi metodami, aby bezpieczniej udostępniać treści aplikacji innym aplikacjom:
- W razie potrzeby wymuś uprawnienia tylko do odczytu lub tylko do zapisu.
-
Zapewnij klientom jednorazowy dostęp do danych za pomocą flag
FLAG_GRANT_READ_URI_PERMISSIONiFLAG_GRANT_WRITE_URI_PERMISSION. - Podczas udostępniania danych używaj identyfikatorów URI
content://, a niefile://. InstancjeFileProviderrobią to za Ciebie.
Poniższy fragment kodu pokazuje, jak używać flag przyznawania uprawnień do identyfikatora URI i uprawnień mechanizmu dostarczania treści, aby wyświetlać plik PDF aplikacji w osobnej aplikacji do wyświetlania plików PDF:
Kotlin
// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("<b>content:</b>//com.example/personal-info.pdf")
// This flag gives the started app read access to the file.
<b>addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)</b>
}.also { intent ->
// Make sure that the user has a PDF viewer app installed on their device.
intent.resolveActivity(packageManager)?.run {
startActivity(intent)
}
}
Java
// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent viewPdfIntent = new Intent(Intent.ACTION_VIEW);
viewPdfIntent.setData(Uri.parse("<b>content://</b>com.example/personal-info.pdf"));
// This flag gives the started app read access to the file.
<b>viewPdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);</b>
// Make sure that the user has a PDF viewer app installed on their device.
if (viewPdfIntent.resolveActivity(getPackageManager()) != null) {
startActivity(viewPdfIntent);
}
Uwaga: wykonywanie plików z katalogu głównego aplikacji z możliwością zapisu jest naruszeniem zasady W^X.
Z tego powodu niezaufane aplikacje kierowane na Androida 10 (poziom interfejsu API 29) lub nowszego nie mogą wywoływać funkcji exec() na plikach w katalogu głównym aplikacji, a jedynie na kodzie binarnym umieszczonym w pliku APK aplikacji.
Dodatkowo aplikacje kierowane na Androida 10 lub nowszego nie mogą w pamięci modyfikować kodu wykonywalnego z plików otwartych za pomocą dlopen(). Obejmuje to wszystkie pliki obiektów współdzielonych (.so) z relokacjami tekstu.
Powiązane informacje:
android:grantUriPermissions
Bezpieczne przechowywanie danych
Chociaż Twoja aplikacja może wymagać dostępu do poufnych informacji o użytkownikach, użytkownicy przyznają jej dostęp do swoich danych tylko wtedy, gdy mają pewność, że odpowiednio je chronisz.
Przechowywanie danych prywatnych w pamięci wewnętrznej
Przechowuj wszystkie prywatne dane użytkownika w pamięci wewnętrznej urządzenia, która jest odizolowana dla każdej aplikacji. Twoja aplikacja nie musi prosić o uprawnienia do wyświetlania tych plików, a inne aplikacje nie mają do nich dostępu. Dodatkowym środkiem bezpieczeństwa jest to, że gdy użytkownik odinstaluje aplikację, urządzenie usuwa wszystkie pliki, które aplikacja zapisała w pamięci wewnętrznej.
Poniższy fragment kodu pokazuje jeden ze sposobów zapisywania danych w pamięci wewnętrznej:
Kotlin
// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
val FILE_NAME = "sensitive_info.txt"
val fileContents = "This is some top-secret information!"
File(filesDir, FILE_NAME).bufferedWriter().use { writer ->
writer.write(fileContents)
}
Java
// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
final String FILE_NAME = "sensitive_info.txt";
String fileContents = "This is some top-secret information!";
try (BufferedWriter writer =
new BufferedWriter(new FileWriter(new File(getFilesDir(), FILE_NAME)))) {
writer.write(fileContents);
} catch (IOException e) {
// Handle exception.
}
Poniższy fragment kodu pokazuje operację odwrotną, czyli odczytywanie danych z pamięci wewnętrznej:
Kotlin
val FILE_NAME = "sensitive_info.txt"
val contents = File(filesDir, FILE_NAME).bufferedReader().useLines { lines ->
lines.fold("") { working, line ->
"$working\n$line"
}
}
Java
final String FILE_NAME = "sensitive_info.txt";
StringBuffer stringBuffer = new StringBuffer();
try (BufferedReader reader =
new BufferedReader(new FileReader(new File(getFilesDir(), FILE_NAME)))) {
String line = reader.readLine();
while (line != null) {
stringBuffer.append(line).append('\n');
line = reader.readLine();
}
} catch (IOException e) {
// Handle exception.
}
Powiązane informacje:
Przechowywanie danych w pamięci zewnętrznej na podstawie przypadku użycia
Używaj pamięci zewnętrznej do przechowywania dużych, niepoufnych plików, które są specyficzne dla Twojej aplikacji, oraz plików, które Twoja aplikacja udostępnia innym aplikacjom. Konkretne interfejsy API, których używasz, zależą od tego, czy aplikacja ma uzyskiwać dostęp do plików aplikacji czy do plików udostępnionych.
Jeśli plik nie zawiera informacji prywatnych ani poufnych, ale jest przydatny dla użytkownika tylko w Twojej aplikacji, przechowuj go w katalogu aplikacji w pamięci zewnętrznej.
Jeśli aplikacja musi uzyskać dostęp do pliku, który jest przydatny dla innych aplikacji, lub go zapisać, użyj jednego z tych interfejsów API, w zależności od przypadku użycia:
- Pliki multimedialne: aby przechowywać i uzyskiwać dostęp do obrazów, plików audio i filmów udostępnianych między aplikacjami, użyj interfejsu Media Store API.
- Inne pliki: aby przechowywać inne typy udostępnionych plików, w tym pobrane pliki, i uzyskiwać do nich dostęp, użyj platformy Storage Access Framework.
Sprawdzanie dostępności woluminu pamięci masowej
Jeśli aplikacja współdziała z wymiennym zewnętrznym urządzeniem pamięci masowej, pamiętaj, że użytkownik może je usunąć, gdy aplikacja próbuje uzyskać do niego dostęp. Uwzględnij logikę, która sprawdza, czy urządzenie pamięci masowej jest dostępne.
Sprawdzanie poprawności danych
Jeśli aplikacja korzysta z danych z pamięci zewnętrznej, upewnij się, że nie zostały one uszkodzone ani zmodyfikowane. Uwzględnij logikę obsługi plików, które nie są już w stabilnym formacie.
Poniższy fragment kodu zawiera przykład weryfikatora skrótu:
Kotlin
val hash = calculateHash(stream)
// Store "expectedHash" in a secure location.
if (hash == <var>expectedHash</var>) {
// Work with the content.
}
// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
suspend fun calculateHash(stream: InputStream): String {
return withContext(Dispatchers.IO) {
val digest = MessageDigest.getInstance("SHA-512")
val digestStream = DigestInputStream(stream, digest)
while (digestStream.read() != -1) {
// The DigestInputStream does the work; nothing for us to do.
}
digest.digest().joinToString(":") { "%02x".format(it) }
}
}
Java
Executor threadPoolExecutor = Executors.newFixedThreadPool(4);
private interface HashCallback {
void onHashCalculated(@Nullable String hash);
}
boolean hashRunning = calculateHash(inputStream, threadPoolExecutor, hash -> {
if (Objects.equals(hash, <var>expectedHash</var>)) {
// Work with the content.
}
});
if (!hashRunning) {
// There was an error setting up the hash function.
}
private boolean calculateHash(@NonNull InputStream stream,
@NonNull Executor executor,
@NonNull HashCallback hashCallback) {
final MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException nsa) {
return false;
}
// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
executor.execute(() -> {
String hash;
try (DigestInputStream digestStream =
new DigestInputStream(stream, digest)) {
while (digestStream.read() != -1) {
// The DigestInputStream does the work; nothing for us to do.
}
StringBuilder builder = new StringBuilder();
for (byte aByte : digest.digest()) {
builder.append(String.format("%02x", aByte)).append(':');
}
hash = builder.substring(0, builder.length() - 1);
} catch (IOException e) {
hash = null;
}
final String calculatedHash = hash;
runOnUiThread(() -> hashCallback.onHashCalculated(calculatedHash));
});
return true;
}
Używanie pamięci wewnętrznej do przechowywania poufnych danych w pamięci podręcznej
Aby zapewnić szybszy dostęp do danych aplikacji, przechowuj je w pamięci podręcznej urządzenia. W przypadku pamięci podręcznych o rozmiarze 1 MB lub mniejszym użyj getCacheDir().
W przypadku pamięci podręcznych większych niż 1 MB użyj getExternalCacheDir().
Obie metody zwracają obiekt File, który zawiera dane z pamięci podręcznej aplikacji.
Katalog wewnętrznej pamięci podręcznej (udostępniany przez getCacheDir()) jest prywatny dla Twojej aplikacji, ale katalog zewnętrznej pamięci podręcznej nie jest.
Poniższy fragment kodu pokazuje, jak zapisać w pamięci podręcznej plik, który został niedawno pobrany przez aplikację:
Kotlin
val cacheFile = File(myDownloadedFileUri).let { fileToCache ->
File(cacheDir.path, fileToCache.name)
}
Java
File cacheDir = getCacheDir();
File fileToCache = new File(myDownloadedFileUri);
String fileToCacheName = fileToCache.getName();
File cacheFile = new File(cacheDir.getPath(), fileToCacheName);
Uwaga: jeśli używasz getExternalCacheDir() do umieszczania pamięci podręcznej aplikacji w pamięci współdzielonej, użytkownik może wysunąć nośnik zawierający tę pamięć, gdy aplikacja jest uruchomiona. Uwzględnij logikę, która pozwoli prawidłowo obsłużyć brak w pamięci podręcznej spowodowany tym zachowaniem użytkownika.
Uwaga: pliki w katalogu zewnętrznej pamięci podręcznej nie są zabezpieczone.
Dlatego każda aplikacja kierowana na Androida 10 (API na poziomie 29) lub starszego, która ma uprawnienie WRITE_EXTERNAL_STORAGE, może uzyskać dostęp do zawartości tej pamięci podręcznej.
Powiązane informacje: Omówienie przechowywania danych i plików
Używanie SharedPreferences w trybie prywatnym
Gdy używasz getSharedPreferences() do tworzenia obiektów SharedPreferences aplikacji lub uzyskiwania do nich dostępu, używaj MODE_PRIVATE. Dzięki temu tylko Twoja aplikacja będzie miała dostęp do informacji w pliku udostępnionych ustawień.
Jeśli chcesz udostępniać dane między aplikacjami, nie używaj obiektów SharedPreferences. Zamiast tego wykonaj czynności opisane w artykule Bezpieczne udostępnianie danych między aplikacjami.
Powiązane informacje:
Aktualizowanie usług i zależności
Większość aplikacji używa zewnętrznych bibliotek i informacji o systemie urządzenia do wykonywania specjalistycznych zadań. Aktualizując zależności aplikacji, zwiększasz bezpieczeństwo tych punktów komunikacji.
Sprawdzanie dostawcy zabezpieczeń usług Google Play
Uwaga: ta sekcja dotyczy tylko aplikacji kierowanych na urządzenia, na których są zainstalowane usługi Google Play.
Jeśli Twoja aplikacja korzysta z usług Google Play, upewnij się, że są one zaktualizowane na urządzeniu, na którym jest zainstalowana. Przeprowadź sprawdzenie asynchronicznie, poza wątkiem UI. Jeśli urządzenie nie jest aktualne, wywołaj błąd autoryzacji.
Aby sprawdzić, czy usługi Google Play są aktualne na urządzeniu, na którym jest zainstalowana Twoja aplikacja, wykonaj czynności opisane w przewodniku na temat aktualizowania dostawcy zabezpieczeń w celu ochrony przed lukami w zabezpieczeniach SSL.
Powiązane informacje:
Zaktualizuj wszystkie zależności aplikacji
Przed wdrożeniem aplikacji upewnij się, że wszystkie biblioteki, pakiety SDK i inne zależności są aktualne:
- W przypadku zależności własnych, takich jak pakiet Android SDK, użyj narzędzi do aktualizowania dostępnych w Android Studio, np. SDK Managera.
- W przypadku zależności od innych firm sprawdź witryny bibliotek, których używa Twoja aplikacja, i zainstaluj wszystkie dostępne aktualizacje oraz poprawki zabezpieczeń.
Powiązane informacje: dodawanie zależności kompilacji
Więcej informacji
Aby dowiedzieć się, jak zwiększyć bezpieczeństwo aplikacji, zapoznaj się z tymi materiałami:
- Lista kontrolna zabezpieczeń dotycząca ogólnej jakości aplikacji
- Program ulepszania zabezpieczeń aplikacji
- Kanał dla deweloperów aplikacji na Androida w YouTube
- Zabezpieczone potwierdzenie w Androidzie: nowy poziom bezpieczeństwa transakcji