¿Es segura la App Radar Covid? Conclusión después de investigar la App.

Como bien sabrás ya, el Gobierno de España con la ayuda de las comunidades autónomas, ha lanzado una App para notificar contactos con personas infectadas por el Covid-19.

¿Donde está 100% funcional?

Actualmente se encuentra en fase piloto, y solo está disponible en las siguientes comunidades autónomas:

  • Andalucía
  • Cantabria
  • Aragón
  • Canarias
  • Extremadura
  • Castilla y León

Se prevé que esté disponible en todas las comunidades autónomas para el mes de Septiembre.

Su funcionamiento

La App es muy sencilla de utilizar y su funcionamiento es tan simple como rastrear los dispositivos móviles que tienes alrededor en todo momento. No almacena datos sobre el terminal, sino que almacena una lista de números aleatorios y dinámicos asociados a los terminales con los que te cruzas, y según confirma el Gobierno, se almacena en la memoria local del dispositivo, lo que garantiza cierta privacidad.

En iOS solo pide permisos de bluetooth y en Android pide permisos de bluetooth y ubicación. Según Google, solicita permisos de ubicación como requisito del sistema para poder usar el Bluetooth de baja energía. (Habría que ver por qué en el sistema operativo de Apple esto no es un requisito).

Privacidad

Al parecer se ha hecho mucho hincapié en garantizar la privacidad de los usuarios de la App y en principio no se debe de tener miedo a instalarla. Si comparamos los permisos del sistema que solicita Radar Covid, con los permisos que solicitan las Apps más instaladas…

RADAR COVIDWHATSAPPFACEBOOKINSTAGRAMTWITTERSPOTIFYTIKTOK
PERMISO DE CÁMARANo
PERMISO DE ACCESO A CONTACTOSNo
PERMISO DE ACCESO AL ALMACENAMIENTONo
PERMISO DE ACCESO AL MICRÓFONONo
PERMISO DE CONEXIÓN A REDNo
PERMISO DE UBICACIÓNNoNoNoNo
PERMISO DE ACCESO AL CALENDARIONoNoNoNoNoNo
PERMISO DE TELÉFONO (LLAMAR)NoNoNo
PERMISO DE SMSNoNoNoNoNo
Comparativa de permisos solicitados por distintas Apps conocidas

Ingeniería Inversa

Como me picaba la curiosidad sobre como funciona esta App, he hecho un proceso sencillo de ingeniería inversa para verle las tripas. Empecemos, pero antes dejar claro que este proceso es legal según el artículo 100.3 de la Ley de Propiedad Intelectual

establece que el usuario legítimo de una copia de un programa de ordenador puede analizar o estudiar su funcionamiento, aun sin contar con la autorización expresa del titular de dicho programa, siempre que lo haga durante la normal ejecución del mismo, en sus distintas modalidades, que tiene derecho a hacer como legítimo poseedor de tal copia.

Art. 100.3 LPI: “El usuario legítimo de la copia de un programa estará facultado para observar, estudiar o verificar su funcionamiento, sin autorización previa del titular, con el fin de determinar las ideas y principios implícitos en cualquier elemento del programa, siempre que lo haga durante cualquiera de las operaciones de carga, visualización, ejecución, transmisión o almacenamiento del programa que tiene derecho a hacer”.

Vigencia desde 23 de Abril de 1996. Revisión vigente desde 09 de Julio de 2020

  • Manifiesto de permisos
"permissions": ["android.permission.INTERNET", 
                    "android.permission.ACCESS_NETWORK_STATE", 
                    "android.permission.BLUETOOTH", 
                    "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", 
                    "android.permission.RECEIVE_BOOT_COMPLETED", 
                    "android.permission.WAKE_LOCK", 
                    "android.permission.FOREGROUND_SERVICE", 
                    "com.google.android.c2dm.permission.RECEIVE",
                    "com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE"],

Ese es el manifiesto de permisos del fichero manifest.json.

Intermanente usa:

  1. Conexión a Internet (android.permission.INTERNET y android.permission.ACCESS_NETWORK_STATE): Algo normal ya que compara la lista de números aleatorios que tienes en local con la lista de números aleatorios que han reportado estar infectados a través de la App.
  2. Uso del Bluetooth (android.permission.BLUETOOTH): Lógicamente para rastrear los dispositivos cercanos.
  3. Omisión del modo ahorro de batería (android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS): Este permiso permite que se ignore el modo ahorro de batería de Android, ya que sin este permiso la App no se podría ejecutar en segundo plano.
  4. Iniciar App automáticamente al encender o reiniciar el teléfono (android.permission.RECEIVE_BOOT_COMPLETED): Muy útil para que los usuarios se despreocupen de iniciarla en caso de apagado o reinicio del smartphone.
  5. Permisos de no suspensión (android.permission.WAKE_LOCK): Para evitar agotar la batería, un dispositivo Android que se deja inactivo se duerme rápidamente. Sin embargo, hay ocasiones en las que una aplicación necesita activar la pantalla o la CPU y mantenerla activa para completar algún trabajo, como por ejemplo sincronizar la lista de números aleatorios que han sido contagiados.
  6. Permisos de ejecución en primer plano (android.permission.FOREGROUND_SERVICE): Las apps que están orientadas a Android 9 o versiones posteriores y usan los servicios en primer plano deben solicitar el permiso FOREGROUND_SERVICE. Es un permiso que todas las Apps tienen.
  7. Permisos para recibir información de un servidor GCM (com.google.android.c2dm.permission.RECEIVE): Para comunicarse con la API de Android y descargarse la lista de usuarios reportados como infectados.
  8. Dependencia añadida automáticamente por el compilador de Android (com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE). Todas las Apps de la Google Play lo tienen, y solo sirve para detectar si la aplicación se ha instalado desde un anuncio de Google.

Pues después de desmontar el manifiesto de permisos que la App usa internamente, parece que no es nada intrusiva. Lo único que puede molestar un poco es que ignora el modo ahorro de batería, pero que primas más ¿Tu salud o la batería de tu teléfono?

Ahora falta saber como maneja la información…

¿Utiliza protocolos seguros como HTTPS para encriptar el trafico Web? ¿Utiliza Autenticación por Java Web Token? ¿En caso de usar Java Web Token, tiene siempre el mismo token de autenticación o es dinámico? vamos a ello.

Función ejecutada al abrir la App, ubicada en RadarCovidAplication.java:

Como se muestra, se utiliza protocolo https (maravilloso, el trafico va encriptado) sin embargo usa una clave pública que está demasiado accesible, pero eso es cuestión de gustos.

He quitado los últimos 30 caracteres para evitar abusos con el endpoint. Si alguien quiere hacer el mal, que descompile el APK y se moleste en bucear en el código fuente…

    public void onCreate() {
        super.onCreate();
        C2286e.f6256e = C0701f.f2150e;
        String str = "https://radarcovid.covid19.gob.es/dp3t/";
        ApplicationInfo applicationInfo = new ApplicationInfo(getPackageName(), str, str);
        try {
            PublicKey d = C0967p0.m2250d("LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFdmx1bzYyTFVVcFllcVVGM3haWVhYSG03cjBGWApScENFbVBqTUlxUHVERjcvYmRua1FIbndxbVNoVzIvOU9BcllEd09FUUZmdEE4ZDV6T3NEZmh0T2NRPT0KLS");
            applicationInfo.getAppId();
            C5195d b = C5195d.m11631b((Context) this);
            if (b != null) {
                applicationInfo.getAppId();
                b.f12413a.edit().putString("application", C5243a.m11696a(applicationInfo)).apply();
                b.f12413a.edit().putBoolean("devHistory", false).apply();
                SyncWorker.f2669i = d;
                C5242m.m11680a((Context) this).mo11964a(b.f12413a.getInt("attenuationThresholdLow", 50), b.f12413a.getInt("attenuationThresholdMedium", 60));
                Context applicationContext = getApplicationContext();
                if (!C5178e.f12367a) {
                    applicationContext.registerReceiver(new C5198f(), new IntentFilter("android.bluetooth.adapter.action.STATE_CHANGED"));
                    applicationContext.registerReceiver(new C5202h(), new IntentFilter("android.location.MODE_CHANGED"));
                    applicationContext.registerReceiver(new C5197e(), new IntentFilter("android.os.action.POWER_SAVE_WHITELIST_CHANGED"));
                    applicationContext.registerReceiver(new C5206j(), new IntentFilter("org.dpppt.android.sdk.ACTION_UPDATE_ERRORS"));
                    C0967p0.m2200a(applicationContext, null);
                    C0967p0.m2199a(applicationContext);
                }
              
            throw null;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }

Comprobaciones trampa en la clase ConfirmationActivity.java

Las llamadas a los endpoint están cifrados por HTTPS pero no comprendo por que se hacen verificaciones para que acepte HTTP (no cifrado) en caso de fallar la llamada cifrada.

public void onCreate(Bundle bundle) {
        Uri uri;
        String str;
        super.onCreate(bundle);
        setContentView((int) R.layout.activity_confirmation);
        C0500a R = mo3873R();
        String obj = R.mo3714a("MY_HEALTH_REPORTED_INFO_URL", 
                               R.f1897b.getText(R.string.exposure_detail_info_url)).toString();
        String str2 = "http://";
        if (C4681g.m10318a((CharSequence) obj, (CharSequence) str2, false, 2) ||
           C4681g.m10318a((CharSequence) obj, (CharSequence) "https://", false, 2)) {
            uri = Uri.parse(obj);
            str = "Uri.parse(infoUrl)";
        } else {
            StringBuilder sb = new StringBuilder();
            sb.append(str2);
            sb.append(obj);
            uri = Uri.parse(sb.toString());
            str = "Uri.parse(\"http://$infoUrl\")";
        }
        C4638h.m10270a((Object) uri, str);
        int i = C0699d.buttonMoreInfo;
        if (this.f1732w == null) {
            this.f1732w = new HashMap();
        }
        View view = (View) this.f1732w.get(Integer.valueOf(i));
        if (view == null) {
            view = findViewById(i);
            this.f1732w.put(Integer.valueOf(i), view);
        }
        ((MoreInfoButton) view).setOnClickListener(new C0520a(this, uri));
    }

CovidReportActivity.java reporta al servidor el usuario infectado cuando inserta el código de su prueba PCR.

Dentro de la clase, hay un sistema ofuscado de elementos basado en un HashMap con los elementos necesarios para enviar el reporte. Algo que parece muy seguro para gente que hace la ingeniería inversa ya que llevaría mucho tiempo comprender como funciona el envío del reporte.

    /* renamed from: es.gob.radarcovid.features.covidreport.form.view.CovidReportActivity$a */
    public static final class C0392a extends C4639i implements C4618l<C1034d, C4560l> {
        /* renamed from: f */
        public final /* synthetic */ CovidReportActivity f1735f;
        public C0392a(CovidReportActivity covidReportActivity) {
            this.f1735f = covidReportActivity;
            super(1);
        }
        /* renamed from: b */
        public Object mo3153b(Object obj) {
            C1034d dVar = (C1034d) obj;
            if (dVar != null) {
                dVar.dismiss();
                this.f1735f.mo3145T().mo3752c();
                return C4560l.f10773a;
            }
            C4638h.m10271a("it");
            throw null;
        }
    }

Conclusión:

Es una App que implementa bastantes medidas para preservar la privacidad, no es nada intrusiva y es 100% anónima.

Como hemos visto, todas las conexiones las hace mediante https pero en todas las llamadas menos en la de instalación hace una verificación para que si falla la conexión https, proceda a hacer una conexión http.

Bajo mi punto de vista este es el eslabón más débil debido a que si estás en una red pública, alguien podría hacer un ataque Man In The Middle forzando el uso de http con SSLstrip, saltarse el cifrado y ver toda la comunicación de la App con el servidor. Pero tampoco se obtendría ningún dato «valioso» debido a que los mapas de IDs de usuarios no se relacionan con ninguna persona de forma directa.

Seguramente saquen actualizaciones e irán mejorando, pero en primera instancia yo la tengo instalada ya que después de destriparla puedo decir que me fío de ella. Te animo a que te la instales y colabores en la extinción de la pandemia.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *