Android nutzt ein SicherheitsProvider
, um eine sichere Netzwerkkommunikation zu ermöglichen. Gelegentlich
Sicherheitslücken werden beim Standard-Sicherheitsanbieter gefunden. Um vor diesen Sicherheitslücken zu schützen, bieten die Google Play-Dienste die Möglichkeit, den Sicherheitsanbieter eines Geräts automatisch zu aktualisieren, um vor bekannten Exploits zu schützen. Wenn Sie Methoden der Google Play-Dienste aufrufen, können Sie dafür sorgen, dass Ihre App auf einem Gerät ausgeführt wird, das die neuesten Updates hat, um vor bekannten Exploits zu schützen.
So wurde beispielsweise eine Sicherheitslücke in OpenSSL (CVE-2014-0224) entdeckt, die Apps anfällig für einen On-Path-Angriff macht, bei dem sicherer Traffic ohne Wissen der jeweiligen Seite entschlüsselt wird. In der Version 5.0 der Google Play-Dienste ist eine Korrektur verfügbar. Apps müssen jedoch prüfen, ob diese Korrektur installiert ist. Von können Sie mithilfe der Methoden der Google Play-Dienste sicherstellen, auf einem Gerät ab, das gegen diesen Angriff gesichert ist.
Achtung : Aktualisierung der Sicherheitseinstellungen eines Geräts
Provider
wird nicht aktualisiert
android.net.SSLCertificateSocketFactory
,
das angreifbar bleibt. Wir empfehlen App-Entwicklern, anstelle dieser eingestellten Klasse höhere Methoden für die Interaktion mit der Kryptografie zu verwenden, z. B. HttpsURLConnection
.
Sicherheitsanbieter mit ProviderInstaller patchen
Wenn Sie den Sicherheitsanbieter eines Geräts aktualisieren möchten, verwenden Sie die
ProviderInstaller
. Sie können überprüfen, ob der
Sicherheitsanbieter auf dem neuesten Stand ist,
wenn nötig), indem Sie uns anrufen.
dieser Kurs ist installIfNeeded()
(oder installIfNeededAsync()
)
. In diesem Abschnitt werden diese Optionen grob beschrieben. In den folgenden Abschnitten finden Sie detailliertere Schritte und Beispiele.
Wenn Sie installIfNeeded()
aufrufen, geschieht Folgendes:
- Wenn die
Provider
des Geräts erfolgreich aktualisiert wurde (oder bereits auf dem neuesten Stand ist), gibt die Methode den Wert zurück, ohne eine Ausnahme auszulösen. - Wenn die Google Play-Dienste-Bibliothek des Geräts nicht auf dem neuesten Stand ist, wirft die Methode
GooglePlayServicesRepairableException
. Die App kann diese Ausnahme dann abfangen und dem Nutzer ein entsprechendes Dialogfeld zum Aktualisieren der Google Play-Dienste anzeigen. - Wenn ein nicht wiederherstellbarer Fehler auftritt, wirft die Methode
GooglePlayServicesNotAvailableException
auf, um anzugeben, dass dieProvider
nicht aktualisiert werden kann. Die App kann dann die Ausnahme abfangen und eine geeignete Maßnahme auswählen, z. B. das Standard-Fehlerbehebungs-Ablaufsdiagramm anzeigen.
Die
installIfNeededAsync()
verhält sich ähnlich, mit dem Unterschied, dass statt der
Ausnahmen ausgelöst, ruft er die entsprechende Callback-Methode auf, um anzugeben,
Erfolg oder Misserfolg.
Wenn der Sicherheitsanbieter bereits auf dem neuesten Stand ist, dauert installIfNeeded()
nur einen Bruchteil der Zeit. Wenn die Methode eine neue Provider
installieren muss, kann dies zwischen 30 und 50 ms (auf neueren Geräten) bis 350 ms (auf älteren Geräten) dauern. So vermeiden Sie Beeinträchtigungen der Nutzererfahrung:
- Anruf
installIfNeeded()
sofort nach dem Laden der Threads aus dem Hintergrundnetzwerk-Threads anstatt darauf zu warten, dass der Thread versucht, das Netzwerk zu nutzen. (Es gibt keinen Schaden an, beim mehrfachen Aufrufen der Methode, da sie sofort zurückgibt, Sicherheitsanbieter nicht aktualisiert werden muss.) - Rufen Sie die asynchrone
Version der Methode,
installIfNeededAsync()
, wenn der Thread die Nutzerfreundlichkeit beeinträchtigen kann blockieren, z. B. wenn der Aufruf aus einer Aktivität im UI-Thread stammt. In diesem Fall müssen Sie warten, bis der Vorgang abgeschlossen ist, bevor Sie eine sichere Kommunikation starten. DieProviderInstaller
ruft die MethodeonProviderInstalled()
des Listeners auf, Methode, um Erfolg zu signalisieren.)
Warnung: Wenn auf dem ProviderInstaller
kein aktualisierter Provider
installiert werden kann, ist der Sicherheitsanbieter Ihres Geräts möglicherweise anfällig für bekannte Exploits. Ihre App sollte sich so verhalten, als wäre die gesamte HTTP-Kommunikation unverschlüsselt.
Sobald die Provider
aktualisiert wurde, werden alle Aufrufe von Sicherheits-APIs (einschließlich SSL-APIs) über sie weitergeleitet.
Dies gilt jedoch nicht für android.net.SSLCertificateSocketFactory
, das weiterhin anfällig für Exploits wie CVE-2014-0224 ist.
Synchron patchen
Die einfachste Methode zum Patchen des Sicherheitsanbieters besteht darin, den synchronen
installIfNeeded()
-Methode.
Dies ist geeignet, wenn die Thread-Blockierung nicht die Nutzererfahrung beeinträchtigt.
bis der Vorgang abgeschlossen ist.
Hier ist beispielsweise eine Implementierung eines Workers, der den Sicherheitsanbieter aktualisiert. Da ein Worker im Hintergrund ausgeführt wird, ist es in Ordnung, wenn der Thread blockiert, während er auf die Aktualisierung des Sicherheitsanbieters wartet. Der Worker ruft installIfNeeded()
auf, um den Sicherheitsanbieter zu aktualisieren. Wenn die Methode normal zurückgegeben wird, weiß der Mitarbeiter, dass der Sicherheitsanbieter auf dem neuesten Stand ist. Wenn die Methode eine Ausnahme auslöst, kann der Worker entsprechende Maßnahmen ergreifen, z. B. den Nutzer auffordern, die Google Play-Dienste zu aktualisieren.
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(); } }
Asynchron patchen
Das Aktualisieren des Sicherheitsanbieters kann bis zu 350 ms (bei
ältere Geräte). Wenn Sie die Aktualisierung in einem Thread ausführen, der sich direkt auf die Nutzerfreundlichkeit auswirkt, z. B. im UI-Thread, sollten Sie keinen synchronen Aufruf zum Aktualisieren des Anbieters ausführen, da dies dazu führen kann, dass die App oder das Gerät einfriert, bis der Vorgang abgeschlossen ist. Verwenden Sie stattdessen die asynchrone
installIfNeededAsync()
-Methode. Diese Methode gibt den Erfolg oder Misserfolg durch Aufrufen von Callbacks an.
Hier ist beispielsweise Code, mit dem der Sicherheitsanbieter in einer Aktivität im UI-Thread aktualisiert wird. Die Aktivität ruft installIfNeededAsync()
auf
um den Anbieter zu aktualisieren und sich selbst als Listener für den Erfolg
oder Fehlerbenachrichtigungen. Ob der Sicherheitsanbieter auf dem neuesten Stand ist
wurde die Aktivität
onProviderInstalled()
wird aufgerufen und die Aktivität weiß, dass die Kommunikation sicher ist. Wenn die
nicht aktualisiert werden kann, ist der Status der Aktivität
onProviderInstallFailed()
wird aufgerufen und die Aktivität kann geeignete Aktionen ausführen (z. B.
Der Nutzer wird aufgefordert, die Google Play-Dienste zu aktualisieren.
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. } }