Un proxy por túnel (Tunnel Proxy) actúa como un intermediario que establece un canal de comunicación ancriptado entre un cliente y un serivdor remoto. Este mecanismo es frecuentemente utilizado para eludir restricciones de red o para añadir una capa extra de seguridad a la comunicación.
Funcionalidades Principales
- Enmascaramiento de Dirección IP: La solicitud hacia el servidor destino proviene desde la dirección IP del servidor proxy, ocultando la IP real del cliente.
- Transmisión Cifrada de Datos: Muchos servicios de proxy por túnel cifran el tráfico que viaja a través del canal, protegeindo la información de intercepciones.
- Gestión de Pool de IPs Dinámico: Proveedores basados en la nube suelen ofrecer un conjunto rotativo de direcciones IP, permitiendo cambios frecuentes para reducir el riesgo de bloqueos por parte del servidor objetivo.
- Simplificación para el Desarrollador: Externalizar la gestión de un pool de IPs a través de un servicio de proxy reduce significativamente la complejidad del código y los costes operativos del proyecto.
Implementación Práctica con Java
A continuación, se muestran ejemplos de cómo configurar una conexión a través de un proxy por túnel utilizando bibliotecas Java comunes. Se asume que ya se cuenta con las credenciales (usuario, contraseña) y los datos de conexión (host, puerto) proporcionados por el servicio de proxy.
Ejemplo con Jsoup
import java.io.IOException;
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class ProxyTunnelJsoup {
private static final String USUARIO_PROXY = "usuario";
private static final String CONTRASENIA_PROXY = "contraseña";
private static final String HOST_PROXY = "tunnel.provider.com";
private static final int PUERTO_PROXY = 12345;
public static void obtenerContenidoViaProxy(String urlObjetivo) {
// Configurar la autenticación para el proxy
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
USUARIO_PROXY,
CONTRASENIA_PROXY.toCharArray()
);
}
});
Proxy proxyConfigurado = new Proxy(
Proxy.Type.HTTP,
new InetSocketAddress(HOST_PROXY, PUERTO_PROXY)
);
try {
Document documento = Jsoup.connect(urlObjetivo)
.proxy(proxyConfigurado)
.timeout(5000)
.get();
if (documento != null) {
System.out.println(documento.body().html());
}
} catch (IOException e) {
System.err.println("Error durante la solicitud: " + e.getMessage());
}
}
public static void main(String[] args) {
String paginaDestino = "https://www.ejemplo.com/pagina";
// Permite la autenticación de proxy para conexiones HTTPS
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
obtenerContenidoViaProxy(paginaDestino);
}
}
Ejemplo con Hutool
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpRequest;
class AutenticadorProxy extends Authenticator {
private final String usuario;
private final String contrasenia;
public AutenticadorProxy(String usuario, String contrasenia) {
this.usuario = usuario;
this.contrasenia = contrasenia;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(usuario, contrasenia.toCharArray());
}
}
public class ProxyTunnelHutool {
private static final String USUARIO = "user";
private static final String CONTRASENIA = "pass123";
private static final String SERVIDOR_PROXY = "proxy.tunnel-service.net";
private static final int PUERTO = 9876;
public static void main(String[] args) {
String urlRecurso = "https://api.ejemplo.com/datos";
// Habilitar autenticación para túneles HTTPS
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
// Establecer el autenticador global
Authenticator.setDefault(new AutenticadorProxy(USUARIO, CONTRASENIA));
// Ejecutar la solicitud HTTP a través del proxy configurado
HttpResponse respuesta = HttpRequest.get(urlRecurso)
.setHttpProxy(SERVIDOR_PROXY, PUERTO)
.timeout(30000)
.execute();
if (respuesta.isOk()) {
System.out.println("Cuerpo de la respuesta: " + respuesta.body());
} else {
System.err.println("La solicitud falló con código: " + respuesta.getStatus());
}
}
}