367 votos

¿Cómo ejecutar un servidor en el puerto 80 como un usuario normal en Linux?

He buscado en Google una solución durante bastante tiempo, pero no he podido encontrar una respuesta.

Estoy en Ubuntu Linux y quiero ejecutar un servidor en el puerto 80, pero debido al mecanismo de seguridad de Ubuntu, me da el siguiente error:

java.net.BindException: Permiso denegado:80

Creo que debería ser bastante sencillo desactivar este mecanismo de seguridad para que el puerto 80 esté disponible para todos los usuarios o asignar los privilegios necesarios al usuario actual para acceder al puerto 80.

3 votos

¿Cuál es el problema de ejecutar el servidor en otro puerto no privilegiado? Usted está pensando en algo tan duro como deshabilitar el mecanismo de seguridad sin proporcionar al menos una razón muy seria para ejecutar un servidor en ese puerto. ¿Está el servidor codificado para enlazar con el puerto 80? Si es así, tíralo.

0 votos

O un mensaje de error de Python: socket.error: [Errno 13] Permission denied

6 votos

402voto

Paul Roub Puntos 11185

Respuesta corta: no se puede. Los puertos por debajo de 1024 sólo pueden ser abiertos por el root. Según el comentario - bueno, se puede, utilizando CAP_NET_BIND_SERVICE Pero este enfoque, aplicado a java bin hará que cualquier programa java se ejecute con esta configuración, lo cual es indeseable, si no un riesgo de seguridad.

La respuesta larga: puedes redirigir las conexiones del puerto 80 a algún otro puerto que puedas abrir como usuario normal.

Ejecutar como root:

# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

Como los dispositivos de loopback (como localhost) no utilizan las reglas de preenrutamiento, si necesita utilizar localhost, etc., añada también esta regla ( gracias @Francesco ):

# iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

NOTA: La solución anterior no es muy adecuado para sistemas multiusuario, ya que cualquier usuario puede abrir el puerto 8080 (o cualquier otro puerto alto que decida utilizar), interceptando así el tráfico. (Créditos a CesarB ).

EDIT: según la pregunta del comentario - para eliminar la regla anterior:

# iptables -t nat --line-numbers -n -L

Esto producirá algo como:

Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:8080 redir ports 8088
2    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 redir ports 8080

La regla que te interesa es la nº 2, así que para eliminarla:

# iptables -t nat -D PREROUTING 2

0 votos

Veo que otros han publicado más rápido que yo. Voy a dejar mi respuesta sólo para la línea de comandos iptables, pero por favor, votar las otras respuestas, no la mía.

18 votos

@Sunny: los upvotes no son para la pistola más rápida del oeste, sino para las mejores respuestas. La tuya es la mejor hasta el momento (yo sólo mencioné iptables; tú realmente proporcionaste la línea de comandos completa). Lo único que tiene la mía que no tiene la tuya es la advertencia de que otros usuarios también pueden enlazar con el puerto 8080.

0 votos

CesarB: de todos modos, tienes tu +1.

86voto

geocar Puntos 1718

Utilice authbind .

Incluso funciona con Java si se habilita la pila de sólo IPv4 de Java. Yo lo uso:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …

4 votos

Si el servidor es Tomcat puede utilizar authbind automáticamente configurando AUTHBIND=yes en /etc/default/tomcat6

0 votos

No he podido conseguir que esto funcione en el servidor Ubuntu con el paquete Java por defecto...

0 votos

Yo tampoco, ¿alguna solución conocida?

47voto

Jake Wharton Puntos 160

Otra solución es hacer su aplicación setuid para que pueda enlazar con el puerto 80. Como root, haz lo siguiente

chown root ./myapp
chmod +S ./myapp

Ten en cuenta que hacer esto, a menos que se haga absolutamente bien, te expondrá a potenciales agujeros de seguridad, porque tu aplicación estará hablando con la red, y se ejecutará con plenos privilegios de root. Si tomas esta solución, deberías mirar el código fuente de Apache o Lighttpd o algo similar, donde usan los privilegios de root para abrir el puerto, pero luego inmediatamente renuncian a esos privilegios y se "convierten" en un usuario con menos privilegios para que un secuestrador no pueda tomar todo tu ordenador.

Actualización: Según lo visto en esta pregunta parece que los kernels de Linux desde la versión 2.6.24 tienen una nueva capacidad que permite marcar un ejecutable (pero no un script, por supuesto) como si tuviera la etiqueta " CAP_NET_BIND_SERVICE ". Si instalas el paquete debian "libcap2-bin", puedes hacerlo emitiendo el comando

setcap 'cap_net_bind_service=+ep' /path/to/program

7 votos

Eso es lo mismo que ejecutar como root, a no ser que la aplicación sepa cómo soltar los privilegios.

17 votos

Esto es peligroso. Esto significa que cualquier petición se ejecutará como root. Es por una razón que incluso apache se inicia como root para enlazar, y luego deja los privilegios a otro usuario.

0 votos

Subvertir las restricciones que tiene Unix para enlazar con el puerto 80 es peligroso, tanto si lo haces con setuid como con iptables.

38voto

xelurg Puntos 1655

Enfoque propuesto por Sunny y CesarB:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

funciona bien, pero tiene un pequeño inconveniente: no evita que el usuario se conecte directamente al puerto 8080 en lugar del 80.

Considere el siguiente escenario cuando esto puede ser un problema.

Digamos que tenemos un servidor que acepta conexiones HTTP en el puerto 8080 y conexiones HTTPS en el puerto 8181.

Utilizamos iptables para establecer las siguientes redirecciones:

80  ---> 8080
443 ---> 8181

Ahora, supongamos que nuestro servidor decide redirigir al usuario de una página HTTP a una página HTTPS. A menos que reescribamos cuidadosamente la respuesta, se redirigiría a https://host:8181/ . En este punto, estamos jodidos:

  • Algunos usuarios marcarían el https://host:8181/ URL y tendríamos que mantener esta URL para no romper sus marcadores.
  • Otros usuarios no podrían conectarse porque sus servidores proxy no admiten puertos SSL no estándar.

Yo utilizo el siguiente enfoque:

iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp --dport 443 -j MARK --set-mark 1
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8181
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -m mark --mark 1 -j ACCEPT
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8181 -m mark --mark 1 -j ACCEPT

Combinado con la regla REJECT por defecto en la cadena INPUT, este enfoque evita que los usuarios se conecten directamente a los puertos 8080, 8181

1 votos

Esto está bien, pero ¿por qué no enlazar el demonio a localhost:8080 en lugar de 0.0.0.0:8080? Quiero hacer eso, pero necesito el iptables para eso.

0 votos

Funciona, realmente genial.

31voto

CesarB Puntos 908

Tradicionalmente en Unix, sólo root puede enlazar con puertos bajos (<1024).

La forma más sencilla de solucionar esto es ejecutar el servidor en un alto (por ejemplo, 8080) y utilizar una regla iptables simple para reenviar las conexiones del puerto 80 al puerto 8080. Ten en cuenta que con esto pierdes la protección extra de los puertos bajos; cualquier usuario de tu máquina puede enlazar con el puerto 8080.

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: