HOWTO · Java
Solucione Java.Net.SocketException: Permiso denegado en Java
Este tutorial demuestra java.net.SocketException: error de permiso denegado en Java.
En esta página
java.net.SocketException: Permission denied significa que una operación de socket fue rechazada por el sistema operativo o una capa de seguridad. El mensaje por sí solo no identifica qué capa la rechazó ni por qué. Empiece por revisar el seguimiento de pila y la operación que intentaba realizar el programa; después, compruebe la política aplicable a esa operación. Los fallos al asociar un socket del servidor y los fallos de conexión del cliente suelen tener causas y soluciones distintas.
Qué significa java.net.SocketException: Permission denied
En última instancia, una llamada de socket de Java depende de que el entorno anfitrión acepte la operación solicitada. La denegación puede deberse a privilegios del sistema operativo, una política del cortafuegos o de seguridad de los endpoints, una política del contenedor o del clúster, o una restricción del entorno de ejecución o de una biblioteca. Son posibilidades que se deben investigar, no causas que el texto de la excepción confirme.
Este mensaje también es distinto de un error que indica que el puerto ya está en uso. Un conflicto de puertos suele mostrar un mensaje específico de dirección en uso. Una denegación de permisos indica que se rechazó la operación; no demuestra que el puerto esté reservado, que la red haya rechazado una conexión ni que Java esté desactualizado. No cambie varios ajustes a la vez: eso dificulta identificar la restricción que realmente se aplica.
Identifique dónde falla la operación de socket
Primero determine si el programa está abriendo un socket de escucha o intentando conectarse a otro host. Un servidor llama a bind para reservar una dirección y un puerto locales. Un cliente normalmente llama a connect para llegar a un endpoint remoto. El seguimiento de pila puede servir de orientación: marcos como Net.bind, ServerSocketChannel.bind o el código de inicio de un conector del servidor apuntan a un intento de asociación local. Son pistas sobre la operación, no pruebas de una política o causa concreta.
Por ejemplo, un seguimiento de inicio de Tomcat que contiene Net.bind y NioEndpoint.bind indica que, durante el arranque, se intentaba asociar un conector local. Compruebe la dirección y el puerto configurados en Tomcat, y compare la hora del fallo con los registros del sistema operativo o del contenedor. Si el seguimiento apunta a una conexión de cliente, anote el host y el puerto de destino e inspeccione la política de salida, el enrutamiento y cualquier configuración de proxy. Un fallo durante la configuración de TLS no significa por sí solo que el certificado haya causado esta denegación del socket; identifique la llamada de socket que falla antes de cambiar la configuración de certificados.
Corrija un error de permisos al asociar un socket del servidor
Un puerto restringido de número bajo es una posible razón por la que un servidor no puede asociar un socket. El umbral y las reglas dependen del sistema operativo y de su configuración; que un puerto sea inferior a 1024 no demuestra que esa sea la causa en todos los hosts. Compruebe el puerto real del conector y la política de privilegios o capacidades del host. Para un servicio de desarrollo o interno, elegir un puerto sin privilegios suele ser la solución más acotada. Actualice la URL del cliente o la asignación del proxy inverso para que coincida. En producción, cuando corresponda, use la configuración de servicio o de reenvío de puertos que admite la plataforma.
Evite iniciar habitualmente Tomcat o todo el proceso de Java como root o Administrador. La ejecución con privilegios elevados concede acceso amplio y puede convertir un fallo de la aplicación en un riesgo para todo el host. Si se necesita un listener privilegiado, prefiera un gestor de servicios, una capacidad o un proxy frontal configurados de forma acotada y compatibles con el sistema operativo; conceda solo el acceso que necesita el servicio.
En OpenShift o en otra plataforma de contenedores, un puerto que funciona en el equipo de desarrollo puede estar prohibido por el contexto de seguridad o el usuario asignado a la carga de trabajo. Compruebe el puerto del contenedor configurado en el despliegue, el usuario efectivo y el contexto de seguridad, así como los eventos de la plataforma y los registros del pod correspondientes al inicio. Use el puerto y la identidad permitidos por la política de la plataforma; no debilite la política de la carga de trabajo ni dé por hecho que el cortafuegos del clúster es responsable sin pruebas.
Compruebe las restricciones del cortafuegos y del entorno de ejecución
Si falla la llamada a connect, compruebe las reglas de salida del cortafuegos o de seguridad de endpoints para el proceso de Java y el destino concreto. Si falla una asociación, compruebe la política local de asociación y cualquier regla de control de aplicaciones que restrinja los sockets de escucha. Revise los registros pertinentes de denegaciones y luego solicite o aplique el cambio de política más acotado para la dirección, el puerto, el sentido del tráfico y el proceso necesarios. Desactivar un cortafuegos o un producto antivirus no es una solución de diagnóstico segura; consulte sus registros o use una regla temporal de alcance limitado, gestionada según los controles habituales de su entorno.
Compruebe también si la aplicación se ejecuta en un contenedor, un entorno aislado, un servicio de alojamiento administrado o bajo una política de seguridad que limite las conexiones de red. Compare el usuario efectivo del entorno de ejecución, las capacidades, el entorno y la política con los de un despliegue que funcione. Una biblioteca de terceros puede imponer sus propios requisitos de configuración, pero consulte su documentación y verifique qué llamada falla antes de cambiar dependencias. Actualizar Java puede ser apropiado por motivos de seguridad o para usar una versión con soporte, pero el texto del error por sí solo no demuestra que la denegación se deba a un entorno de ejecución antiguo.
La propiedad del sistema -Djava.net.preferIPv4Stack=true es una opción de diagnóstico heredada de la era de Java 7 para casos en los que influya la selección de la pila IPv4/IPv6. No concede permisos para asociar sockets ni conectarse, y no debe tratarse como una solución general. Úsela solo cuando el entorno de ejecución y el comportamiento observado de la familia de direcciones la hagan pertinente; prefiera una versión de Java con soporte en vez de adoptar una versión obsoleta para usar esta opción.
Verifique la solución
Antes de cambiar nada, anote la operación, la dirección local o remota, el puerto, la identidad del entorno de ejecución y la política pertinente. Aplique un solo cambio dirigido a una causa y repita la misma operación; luego consulte los mismos registros. En un servidor, confirme que escucha en la dirección y el puerto previstos y que el servicio se inicia con normalidad. En un cliente, confirme que llega al destino previsto y que el servicio remoto acepta la conexión. Si la denegación continúa, la primera causa sospechada no bastaba; siga el diagnóstico con el nuevo seguimiento de pila y los registros de denegaciones, en lugar de conceder privilegios más amplios.
Ejecute este ejemplo:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
public class SocketBindCheck {
public static void main(String[] args) {
try (java.net.ServerSocket socket = new java.net.ServerSocket(0)) {
int assignedPort = socket.getLocalPort();
if (assignedPort > 0 && assignedPort <= 65535) {
System.out.println("Ephemeral port assigned");
} else {
System.out.println("Unexpected port assignment");
}
} catch (java.io.IOException problem) {
System.err.println("Socket could not open: " + problem);
System.exit(1);
}
}
}
Ephemeral port assigned
El puerto solicitado 0 indica al sistema operativo que elija un puerto efímero disponible. La comprobación confirma que el puerto asignado está dentro del intervalo válido de puertos TCP/UDP, mientras que el bloque try-with-resources cierra el socket de escucha. Una ejecución correcta imprime Ephemeral port assigned y termina con estado 0. Esa etiqueta aparece literalmente en inglés en el ejemplo; no está traducida. Si falla la configuración del socket, el programa imprime la IOException y termina con un estado distinto de cero, por lo que la automatización puede distinguir el fallo de configuración del éxito. Consulte los registros y la política de seguridad del host para identificar la causa; esta comprobación no prueba un puerto configurado concreto, la conectividad remota, Tomcat ni una política de OpenShift.
Un puerto fuera del intervalo es un límite distinto: Java lo rechaza antes de pedir al sistema operativo que asocie el socket, por lo que no sirve para diagnosticar una política de permisos. Esta pequeña comprobación detecta ese fallo en el argumento y termina con normalidad:
public class SocketPortBoundaryCheck {
public static void main(String[] args) {
try {
new java.net.ServerSocket(65536).close();
System.out.println("Unexpectedly accepted port");
} catch (IllegalArgumentException problem) {
System.out.println("Port rejected before bind");
} catch (java.io.IOException problem) {
System.out.println("Socket setup failed");
}
}
}