Cómo realizar peticiones API REST a los servicios ocultos de Tor desde un APK de Android

Rafael A. Ortiz    19 mayo, 2020
Cómo realizar peticiones API REST a los servicios ocultos de Tor desde un APK de Android

Nos encontrábamos desarrollando una prueba de concepto en el Área de Innovación y Laboratorio como parte de la arquitectura necesaria para crear un servicio oculto de Tor. También necesitábamos una aplicación móvil para interactuar con ese servicio oculto a través de una API de JSON. Sin embargo parece ser que no hay muchas maneras (bien documentadas) de conseguir esta tarea que parece, en principio, sencilla. Vamos a compartir nuestras notas aquí por si alguien más quisiera ver cómo añadir este soporte a su aplicación.

Si no te interesa la parte de conocimientos previos, avanza un poco más y ve directamente al apartado “Implementación” que encontrarás más abajo.

Contexto

Primero, echemos un vistazo a los diferentes bloques de construcción que necesitaremos para realizar peticiones a un servicio oculto desde nuestra aplicación. En las explicaciones se da por sentado que se tienen nociones básicas de desarrollo de aplicaciones para Tor y Android.

Orbot, NetCipher y el Proyecto Guardian

Orbot es una aplicación gratuita para Android que actúa como un proxy Tor para tu dispositivo. Algo así como si ejecutaras el servicio Tor en tu teléfono, igual que lo harías en cualquier otro sistema Linux. Orbot ha sido desarrollado por el Proyecto Guardian, que crea y mantiene muchas aplicaciones para Android enfocadas en la privacidad. Son el equipo que está detrás de Tor Browser para Android (aprobado oficialmente), así como del combo Orfox+Orbot que vino antes.

Sin embargo, obligar a un usuario a instalar y ejecutar Orbot antes de ejecutar su aplicación no es una experiencia nada grata. Para solucionar esto, se creó NetCipher. NetCipher proporciona, entre otras cosas, una clase de utilidad OrbotHelper que permite a la aplicación comprobar si Orbot está instalado, instar al usuario a que lo instale fácilmente y ejecutar automáticamente Orbot en segundo plano cuando se inicia la aplicación. El proceso es análogo a cuando el paquete del navegador Tor lanza un servicio Tor en segundo plano.

Sin embargo, no es exactamente lo mismo. El actual navegador oficial de Tor para Android elimina NetCipher y Orbot como requisito, y opta por incluir Tor en la propia aplicación. Esto da a los usuarios del navegador Tor una experiencia sencilla e integrada en las diferentes plataformas. Sin embargo, usaremos Orbot ya que su integración es mucho más simple que añadir un demonio Tor a nuestra aplicación.

Volley Library and ProxiedHurlStack

En la página de gitlab de la biblioteca NetCipher se pueden ver los ejemplos proporcionados para muchas bibliotecas HTTP de Android diferentes. Los principales métodos soportados son HttpUrlConnection, OkHttp3, HttpClient y Volley. También hay ejemplos de implementaciones para cada una de estas técnicas.

Por desgracia, estos ejemplos y los artefactos asociados a ellos para otros clientes HTTP no funcionan a la primera. La mayoría de ellos no se han usado prácticamente en, por lo menos, un año, y parece que el método estándar de implementación de Tor ha pasado de NetCipher+Orbot (análogo al proxy de tu instalación FireFox local a través de Tor) a un servicio Tor integrado en el propio APK (análogo al paquete del navegador Tor).

Tras algunos intentos, resulta que en realidad no se necesita el artefacto info.guardianproject.netcipher:netcipher-volley para que Tor funcione en la aplicación. Si echamos un ojo a la fuente de StrongHurlStack.java se puede ver que es bastante sencillo de reimplementar. También dimos con este post de stackoverflow que describe el mismo concepto. El ejemplo no incluye un SSLSocketFactory como lo hace el StrongHurlStack, pero podemos confiar en Tor para que proporcione la encriptación de extremo a extremo y la seguridad de identidad que proporcionaría SSL. Para los servicios ocultos de Tor, SSL es redundante.

Implementación

Para este proceso, asumimos que el usuario ya tiene una API accesible como servicio oculto en somesite.onion.

Las dependencias que hay que añadir al archivo build.gradle del nivel de aplicación son las siguientes:

dependencies {
    implementation 'com.android.volley:volley:1.1.1
    implementation 'info.guardianproject.netcipher:netcipher:2.1.0
}

Asegúrate de actualizar las versiones a las últimas disponibles en el momento de la implementación.

A continuación, crea un archivo y una clase ProxiedHurlStack.java como se describe tanto en los ejemplos de NetCipher como en el post de stackoverflow y añádelo a tu proyecto.

package your.app.here;

import com.android.volley.toolbox.HurlStack;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;

public class ProxiedHurlStack extends HurlStack {
    @Override
    protected HttpUrlConnection createConnection(URL url) throws IOException {
        Proxy proxy = new Proxy(
                Proxy.Type.SOCKS,
                InetSocketAddress.createUnresolved("127.0.0.1", 9050)
        );
        return (HttpURLConnection) url.openConnection(proxy);
    }
}

Ahora en nuestro archivo MainActivity.java podemos importar todas las bibliotecas correspondientes.

package your.app.here;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONObject;

import info.guardianproject.netcipher.proxy.OrbotHelper;

Después, lanzamos una petición a init() e installOrbot() desde nuestro método onCreate()para ejecutar Orbot en segundo plano. Si Orbot ya está instalado, init() devolverá true y pedirá a Orbot que se conecte a la red Tor. Pero si Orbot todavía no está instalado, init() devolverá false y el usuario será redirigido a la Play Store para que instale Orbot. Cuando finalice la instalación, la aplicación le dirá a Orbot que cree una conexión a la red Tor.

@Override
protected void onCreate(Bundle savedInstanceState) {

    // ... other actions here ...

    if (!OrbotHelper.get(this).init()) {
        OrbotHelper.get(this).installOrbot(this);
    }
}

Ahora podemos hacer una petición vía JSON a nuestro servicio oculto. Debes añadir la parte siguiente, sin importar desde dónde envíes peticiones a la API.

JSONObject jsonBody = new JSONObject("{\"your payload\": \"goes here\"}");
RequestQueue queue = Volley.newRequestQueue(this, new ProxiedHurlStack());
String url = "http://somesite.onion/your/api/endpoint/here";

JsonObjectRequest jsonRequest = new JsonObjectRequest(
    Request.Method.POST, url, jsonBody,
    new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            // do something with the response
        }
    },
    new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            // do something with the error
        }
    }
);

queue.add(jsonRequest);

¡Y eso es todo! Ahora puedes probar tu aplicación y ver las peticiones que realiza la API a tu servicio oculto.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.