Skip to content

Most visited

Recently visited

navigation

Cómo actualizar tu proveedor de seguridad para protegerte contra vulnerabilidades de SSL

Android se basa en un Provider de seguridad para proporcionar comunicaciones de red seguras. No obstante, de vez en cuando se encuentran vulnerabilidades en el proveedor de seguridad predeterminado. Para obtener protección contra estas vulnerabilidades, Google Play Services proporciona un método para actualizar automáticamente el proveedor de seguridad de un dispositivo, a fin de brindar protección contra vulnerabilidades conocidas. Al llamar a los métodos de Google Play Services, podrás garantizar que tu app se ejecute en un dispositivo que cuente con las últimas actualizaciones de protección contra vulnerabilidades conocidas.

Por ejemplo, se encontró una vulnerabilidad en OpenSSL (CVE-2014-0224) que puede dejar las apps expuestas a ataques de intermediarios que descifran el tráfico seguro sin que ninguna de las partes lo sepan. En la versión 5.0 de Google Play Services ofrece una solución, pero las apps deben controlar que esta corrección se instale. Al usar los métodos de Google Play Services, podrás garantizar que tu app se ejecute en un dispositivo protegido contra ese ataque.

Advertencia: La actualización del Provider de seguridad de un dispositivo no actualiza android.net.SSLCertificateSocketFactory. En lugar de usar esta clase, recomendamos a los desarrolladores de apps usar métodos de alto nivel para interactuar con criptografía. En la mayoría de las apps se usan API como HttpsURLConnection sin necesidad de configurar un TrustManager personalizado o crear un SSLCertificateSocketFactory.

Aplicación de revisiones en el proveedor de seguridad con ProviderInstaller

Para actualizar el proveedor de seguridad de un dispositivo, usa la clase ProviderInstaller. Puedes verificar que el proveedor de seguridad esté actualizado (y actualizarlo, si fuera necesario) llamando al método installIfNeeded() (o installIfNeededAsync()) de esa clase.

Cuando llamas a installIfNeeded(), ProviderInstaller realiza lo siguiente:

El método installIfNeededAsync() se comporta de forma similar, pero en lugar de generar excepciones llama al método callback correspondiente para indicar el éxito o fracaso.

Si installIfNeeded() necesita instalar un nuevo Provider, esto puede demorar entre 30 y 50 milisegundos en dispositivos más recientes, y hasta 350 en dispositivos más antiguos. Si el proveedor de seguridad ya está actualizado, el tiempo que requiere el método es insignificante. Para evitar afectar la experiencia del usuario:

Advertencia: Si el ProviderInstaller no puede instalar un Provider actualizado, el proveedor de seguridad del dispositivo podría ser vulnerable a ataques conocidos. Tu app debe comportarse como si todas las comunicaciones HTTP estuvieran desencriptadas.

Una vez que se actualice el Provider, todas las llamadas a las API de seguridad (incluidas las API SSL) se direccionarán a través de él. (No obstante, esto no se aplica a android.net.SSLCertificateSocketFactory, que continúa siendo vulnerable a ataques como CVE-2014-0224).

Aplicación de revisiones de forma sincrónica

La forma más simple de aplicar una revisión al proveedor de seguridad es llamar al método sincrónico installIfNeeded(). Es correcto hacer esto cuando la experiencia del usuario no se vea afectada por el bloqueo del subproceso mientras se espera que finalice la operación.

Por ejemplo, a continuación te mostramos la implementación de un adaptador de sincronización que actualiza el proveedor de seguridad. Dado que un adaptador de sincronización se ejecuta en segundo plano, no hay problema si el subproceso se bloquea mientras se espera que se actualice el proveedor de seguridad. El adaptador de sincronización llama a installIfNeeded() para actualizar el proveedor de seguridad. Si el método realiza la devolución normalmente, el adaptador de sincronización reconoce que el proveedor está actualizado. Si el método genera una excepción, el adaptador de sincronización puede tomar la medida necesaria (como solicitar al usuario que actualice Google Play Services).

/**
 * Sample sync adapter using {@link ProviderInstaller}.
 */
public class SyncAdapter extends AbstractThreadedSyncAdapter {

  ...

  // This is called each time a sync is attempted; this is okay, since the
  // overhead is negligible if the security provider is up-to-date.
  @Override
  public void onPerformSync(Account account, Bundle extras, String authority,
      ContentProviderClient provider, SyncResult syncResult) {
    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.
      GooglePlayServicesUtil.showErrorNotification(
          e.getConnectionStatusCode(), getContext());

      // Notify the SyncManager that a soft error occurred.
      syncResult.stats.numIOExceptions++;
      return;

    } catch (GooglePlayServicesNotAvailableException e) {
      // Indicates a non-recoverable error; the ProviderInstaller is not able
      // to install an up-to-date Provider.

      // Notify the SyncManager that a hard error occurred.
      syncResult.stats.numAuthExceptions++;
      return;
    }

    // If this is reached, you know that the provider was already up-to-date,
    // or was successfully updated.
  }
}

Aplicación de revisiones de forma asincrónica

La actualización del proveedor de seguridad puede tardar hasta 350 milisegundos (en dispositivos más antiguos). Si realizas la actualización en un subproceso que afecta directamente la experiencia del usuario, como el subproceso de la IU, no te convendrá realizar una llamada asincrónica para actualizar el proveedor, ya que podría hacer que la app o el dispositivo se congelen hasta que finalice la operación. Como alternativa, debes usar el método asincrónico installIfNeededAsync(). Este método indica el éxito o fracaso llamando a callbacks.

Por ejemplo, a continuación te mostramos parte de un código con el cual se actualiza el proveedor de seguridad en una actividad del subproceso de la IU. La actividad llama a installIfNeededAsync() para actualizar el proveedor y se designa a sí misma como la receptora para recibir notificaciones de éxito o fracaso. Si el proveedor de seguridad está actualizado o se actualizó correctamente, se llama al método onProviderInstalled() de la actividad y esta reconoce que la comunicación es segura. Si no es posible actualizar el proveedor, se llama al método onProviderInstallFailed() de la actividad y esta puede tomar una medida adecuada (como indicar al usuario que actualice Google Play Services).

/**
 * Sample activity using {@link ProviderInstaller}.
 */
public class MainActivity extends Activity
    implements ProviderInstaller.ProviderInstallListener {

  private static final int ERROR_DIALOG_REQUEST_CODE = 1;

  private boolean mRetryProviderInstall;

  //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) {
    if (GooglePlayServicesUtil.isUserRecoverableError(errorCode)) {
      // Recoverable error. Show a dialog prompting the user to
      // install/update/enable Google Play services.
      GooglePlayServicesUtil.showErrorDialogFragment(
          errorCode,
          this,
          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 is not 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 GooglePlayServicesUtil.showErrorDialogFragment
      // before the instance state is restored throws an error. So instead,
      // set a flag here, which will cause the fragment to delay until
      // onPostResume.
      mRetryProviderInstall = true;
    }
  }

  /**
   * On resume, check to see if we flagged that we need to reinstall the
   * provider.
   */
  @Override
  protected void onPostResume() {
    super.onPostResult();
    if (mRetryProviderInstall) {
      // We can now safely retry installation.
      ProviderInstall.installIfNeededAsync(this, this);
    }
    mRetryProviderInstall = false;
  }

  private void onProviderInstallerNotAvailable() {
    // This is reached if the provider cannot be updated for some reason.
    // App should consider all HTTP communication to be vulnerable, and take
    // appropriate action.
  }
}
This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)