Android używa zabezpieczeń Provider
do:
zapewnić bezpieczną komunikację w sieci. Czasami jednak w domyślnym dostawcy zabezpieczeń są wykrywane luki w zabezpieczeniach. Ochrona przed
te luki w zabezpieczeniach, Google Play
usługi umożliwia automatyczne aktualizowanie dostawcy zabezpieczeń urządzenia
w celu ochrony przed znanymi lukami w zabezpieczeniach. Wywołując metody Usług Google Play, możesz upewnić się,
że aplikacja działa na urządzeniu z najnowszymi aktualizacjami
ochrony przed znanymi lukami w zabezpieczeniach.
Na przykład w OpenSSL wykryto lukę w zabezpieczeniach (CVE-2014-0224), która może spowodować, że aplikacje staną się podatne na atak na ścieżce, który umożliwia odszyfrowywanie bezpiecznego ruchu bez wiedzy żadnej ze stron. Wersja Usług Google Play Wersja 5.0 zawiera poprawkę, ale aplikacje muszą sprawdzić, czy jest ona zainstalowana. Korzystając z metod usług Google Play, możesz mieć pewność, że Twoja aplikacja działa na urządzeniu, które jest zabezpieczone przed takim atakiem.
Uwaga: aktualizacja zabezpieczeń urządzenia Provider
nie aktualizuje android.net.SSLCertificateSocketFactory
, które pozostaje podatne na ataki. Zamiast tej przestarzałej klasy zachęcamy deweloperów aplikacji do korzystania z metod wysokiego poziomu do interakcji z kryptografią, takich jak HttpsURLConnection
.
Zainstaluj poprawkę dostawcy zabezpieczeń za pomocą narzędzia ProviderInstaller
Aby zaktualizować dostawcę zabezpieczeń urządzenia, użyj klasy ProviderInstaller
. Możesz sprawdzić, czy dostawca zabezpieczeń jest aktualny (i zaktualizować go,
w razie potrzeby), dzwoniąc do
installIfNeeded()
tych zajęć
(lub installIfNeededAsync()
)
. W tej sekcji omawiamy te opcje w ogólny sposób. W sekcjach poniżej znajdziesz bardziej szczegółowe instrukcje i przykłady.
Gdy wywołasz installIfNeeded()
, usługa ProviderInstaller
:
- Jeśli
Provider
urządzenia zostanie zaktualizowany (lub jest już aktualny), metoda zwróci wartość bez zgłaszania wyjątku. - Jeśli biblioteka Usług Google Play na urządzeniu jest nieaktualna, metoda
GooglePlayServicesRepairableException
. Aplikacja może wtedy zareagować na to wyjątek i wyświetlić użytkownikowi odpowiednie okno dialogowe, aby zaktualizować usługi Google Play. - Jeśli wystąpi błąd nieodwracalny, metoda zwróci błąd
GooglePlayServicesNotAvailableException
aby wskazać, że nie może zaktualizowaćProvider
. Aplikacja wykrywa wyjątek i wybiera odpowiedni takiego działania, jak na przykład wyświetlenie standardowego opisu schemat procesu naprawczego.
Metoda installIfNeededAsync()
działa podobnie, ale zamiast zgłaszać wyjątki, wywołuje odpowiednią metodę wywołania zwrotnego, aby wskazać powodzenie lub niepowodzenie.
Jeśli dostawca zabezpieczeń jest już na bieżąco, installIfNeeded()
zajmuje to pomijalnie krótki czas. Jeśli metoda wymaga zainstalowania nowego Provider
, może to potrwać od 30 do 50 ms (na nowszych urządzeniach) do 350 ms (na starszych urządzeniach). Aby zadbać o wygodę użytkowników:
- wywoływać metodę
installIfNeeded()
z wątków sieciowych w tle natychmiast po ich załadowaniu, zamiast czekać, aż spróbują one użyć sieci. (nie ma znaczenia, czy metoda jest wywoływana wielokrotnie, ponieważ zwraca natychmiastową wartość, jeśli dostawca zabezpieczeń nie wymaga aktualizacji). - Wywołuj asynchroniczną wersję metody
installIfNeededAsync()
, jeśli blokowanie wątku może mieć wpływ na działanie aplikacji – na przykład, jeśli wywołanie pochodzi z aktywności w wątku interfejsu użytkownika. (Jeśli to zrobisz, musisz zaczekać na zakończenie operacji, zanim spróbujesz nawiązać bezpieczne połączenie. FunkcjaProviderInstaller
wywołuje metodęonProviderInstalled()
odbiorcy, aby zasygnalizować sukces.
Ostrzeżenie: jeśli parametr
ProviderInstaller
nie można zainstalować zaktualizowanej wersji Provider
,
dostawca zabezpieczeń urządzenia może być podatny na znane luki w zabezpieczeniach. Twoja aplikacja
powinien działać tak, jakby cała komunikacja HTTP była niezaszyfrowana.
Gdy interfejs Provider
zostanie zaktualizowany, wszystkie wywołania interfejsów API zabezpieczeń (w tym interfejsów API SSL) będą przez niego kierowane.
(Nie dotyczy to jednak android.net.SSLCertificateSocketFactory
, która pozostaje podatna na exploity takie jak CVE-2014-0224).
Synchronicznie
Najprostszym sposobem zastosowania poprawki dostawcy zabezpieczeń jest wywołanie
metoda installIfNeeded()
.
Jest to odpowiednie, jeśli blokowanie wątku nie wpłynie na wrażenia użytkownika podczas oczekiwania na zakończenie operacji.
Oto na przykład implementacja elementu roboczego, który aktualizuje dostawcę zabezpieczeń. Od pracownika
działa w tle, nic nie szkodzi, jeśli wątek blokuje się podczas oczekiwania
, by zaktualizować dostawcę zabezpieczeń. Pracownik dzwoni do firmy installIfNeeded()
, aby poinformować ją o znalezionym urządzeniu. Jeśli metoda zwraca dane prawidłowo, pracownik wie, że dostawca zabezpieczeń jest aktualny. Jeśli metoda zgłosi wyjątek,
może podjąć odpowiednie działania (na przykład poprosić użytkownika o
aktualizacja Usług Google Play).
Kotlin
/** * Sample patch Worker using {@link ProviderInstaller}. */ class PatchWorker(appContext: Context, workerParams: WorkerParameters): Worker(appContext, workerParams) { override fun doWork(): Result { try { ProviderInstaller.installIfNeeded(context) } catch (e: GooglePlayServicesRepairableException) { // Indicates that Google Play services is out of date, disabled, etc. // Prompt the user to install/update/enable Google Play services. GoogleApiAvailability.getInstance() .showErrorNotification(context, e.connectionStatusCode) // Notify the WorkManager that a soft error occurred. return Result.failure() } catch (e: GooglePlayServicesNotAvailableException) { // Indicates a non-recoverable error; the ProviderInstaller can't // install an up-to-date Provider. // Notify the WorkManager that a hard error occurred. return Result.failure() } // If this is reached, you know that the provider was already up to date // or was successfully updated. return Result.success() } }
Java
/** * Sample patch Worker using {@link ProviderInstaller}. */ public class PatchWorker extends Worker { ... @Override public Result doWork() { try { ProviderInstaller.installIfNeeded(getContext()); } catch (GooglePlayServicesRepairableException e) { // Indicates that Google Play services is out of date, disabled, etc. // Prompt the user to install/update/enable Google Play services. GoogleApiAvailability.getInstance() .showErrorNotification(context, e.connectionStatusCode) // Notify the WorkManager that a soft error occurred. return Result.failure(); } catch (GooglePlayServicesNotAvailableException e) { // Indicates a non-recoverable error; the ProviderInstaller can't // install an up-to-date Provider. // Notify the WorkManager that a hard error occurred. return Result.failure(); } // If this is reached, you know that the provider was already up to date // or was successfully updated. return Result.success(); } }
Stosuj poprawki asynchronicznie
Aktualizacja dostawcy zabezpieczeń może potrwać do 350 ms (przy włączonym
starszych urządzeń). Jeśli aktualizujesz wątek, który ma bezpośredni wpływ na wrażenia użytkownika, np. wątek interfejsu użytkownika, nie rób wywołania synchronicznego, aby zaktualizować dostawcę, ponieważ może to spowodować zablokowanie aplikacji lub urządzenia do czasu zakończenia operacji. Zamiast tego użyj asynchronicznej metody installIfNeededAsync()
. Ta metoda wskazuje powodzenie lub niepowodzenie przez wywołanie
.
Oto na przykład kod, który aktualizuje dostawcę zabezpieczeń w aktywności w wątku interfejsu. Aktywność wywołuje funkcję installIfNeededAsync()
, aby zaktualizować dostawcę, i wskazuję siebie jako słuchacza, aby otrzymywać powiadomienia o sukcesie lub niepowodzeniu. Jeśli dostawca zabezpieczeń jest aktualny lub został zaktualizowany, wywoływana jest metoda onProviderInstalled()
aktywności, a ta wie, że komunikacja jest bezpieczna. Jeśli nie można zaktualizować dostawcy, wywoływana jest metoda onProviderInstallFailed()
aktywności, która może podjąć odpowiednie działanie (np. poprosić użytkownika o zaktualizowanie usług Google Play).
Kotlin
private const val ERROR_DIALOG_REQUEST_CODE = 1 /** * Sample activity using {@link ProviderInstaller}. */ class MainActivity : Activity(), ProviderInstaller.ProviderInstallListener { private var retryProviderInstall: Boolean = false // Update the security provider when the activity is created. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ProviderInstaller.installIfNeededAsync(this, this) } /** * This method is only called if the provider is successfully updated * (or is already up to date). */ override fun onProviderInstalled() { // Provider is up to date; app can make secure network calls. } /** * This method is called if updating fails. The error code indicates * whether the error is recoverable. */ override fun onProviderInstallFailed(errorCode: Int, recoveryIntent: Intent) { GoogleApiAvailability.getInstance().apply { if (isUserResolvableError(errorCode)) { // Recoverable error. Show a dialog prompting the user to // install/update/enable Google Play services. showErrorDialogFragment(this@MainActivity, errorCode, ERROR_DIALOG_REQUEST_CODE) { // The user chose not to take the recovery action. onProviderInstallerNotAvailable() } } else { onProviderInstallerNotAvailable() } } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == ERROR_DIALOG_REQUEST_CODE) { // Adding a fragment via GoogleApiAvailability.showErrorDialogFragment // before the instance state is restored throws an error. So instead, // set a flag here, which causes the fragment to delay until // onPostResume. retryProviderInstall = true } } /** * On resume, check whether a flag indicates that the provider needs to be * reinstalled. */ override fun onPostResume() { super.onPostResume() if (retryProviderInstall) { // It's safe to retry installation. ProviderInstaller.installIfNeededAsync(this, this) } retryProviderInstall = false } private fun onProviderInstallerNotAvailable() { // This is reached if the provider can't be updated for some reason. // App should consider all HTTP communication to be vulnerable and take // appropriate action. } }
Java
/** * Sample activity using {@link ProviderInstaller}. */ public class MainActivity extends Activity implements ProviderInstaller.ProviderInstallListener { private static final int ERROR_DIALOG_REQUEST_CODE = 1; private boolean retryProviderInstall; // Update the security provider when the activity is created. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ProviderInstaller.installIfNeededAsync(this, this); } /** * This method is only called if the provider is successfully updated * (or is already up to date). */ @Override protected void onProviderInstalled() { // Provider is up to date; app can make secure network calls. } /** * This method is called if updating fails. The error code indicates * whether the error is recoverable. */ @Override protected void onProviderInstallFailed(int errorCode, Intent recoveryIntent) { GoogleApiAvailability availability = GoogleApiAvailability.getInstance(); if (availability.isUserRecoverableError(errorCode)) { // Recoverable error. Show a dialog prompting the user to // install/update/enable Google Play services. availability.showErrorDialogFragment( this, errorCode, ERROR_DIALOG_REQUEST_CODE, new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { // The user chose not to take the recovery action. onProviderInstallerNotAvailable(); } }); } else { // Google Play services isn't available. onProviderInstallerNotAvailable(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == ERROR_DIALOG_REQUEST_CODE) { // Adding a fragment via GoogleApiAvailability.showErrorDialogFragment // before the instance state is restored throws an error. So instead, // set a flag here, which causes the fragment to delay until // onPostResume. retryProviderInstall = true; } } /** * On resume, check whether a flag indicates that the provider needs to be * reinstalled. */ @Override protected void onPostResume() { super.onPostResume(); if (retryProviderInstall) { // It's safe to retry installation. ProviderInstaller.installIfNeededAsync(this, this); } retryProviderInstall = false; } private void onProviderInstallerNotAvailable() { // This is reached if the provider can't be updated for some reason. // App should consider all HTTP communication to be vulnerable and take // appropriate action. } }