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


He buscado en Google durante bastante tiempo, pero no pude encontrarlo.

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

java.net.BindException: Permiso denegado: 80

Creo que debería ser lo suficientemente simple como para deshabilitar este mecanismo de seguridad para que el puerto 80 esté disponible para todos los usuarios o para asignar los privilegios requeridos al usuario actual para acceder al puerto 80.


281
2017-11-10 14:31


origen


¿Cuál es el problema para ejecutar el servidor en otro puerto que no tiene privilegios? 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 al puerto 80? Si es así, tíralo. - Anonymous
O un mensaje de error de Python: socket.error: [Errno 13] Permission denied - Kazark
posible duplicado de Usuario regular utilizando puertos por debajo de 1024 - Roman
Usted no puede Los puertos por debajo de 1024 son privilegiados y solo la raíz puede abrir sockets de escucha en ellos. Lo apropiado es eliminar los permisos después de abrirlos. - Falcon Momot
"Anónimo": los usuarios del mundo han sido entrenados para buscar ciertos servicios en ciertos puertos. En algunos casos, ha sido estandarizado. Por ejemplo, HTTP en el puerto 80 y HTTPS en el puerto 443. Es difícil cambiar los usuarios y los estándares del mundo. - jww


Respuestas:


Respuesta corta: no puedes. Los puertos por debajo de 1024 solo pueden abrirse por root. Según el comentario - bueno, puedes, usando CAP_NET_BIND_SERVICE, pero ese enfoque, aplicado a java bin hará que cualquier programa Java se ejecute con esta configuración, lo cual es indeseable, si no es un riesgo de seguridad.

La respuesta larga: puede redirigir las conexiones en el puerto 80 a algún otro puerto que pueda 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 bucle invertido (como localhost) no usan las reglas de pre-enrutamiento, si necesita usar localhost, etc., agregue 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 adecuado para sistemas multiusuario, ya que cualquier usuario puede abrir el puerto 8080 (o cualquier otro puerto alto que decida usar), interceptando así el tráfico. (Créditos para CesarB).

EDITAR: 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 le interesa es nr. 2, para borrarlo:

# iptables -t nat -D PREROUTING 2

330
2017-11-10 14:41



@Sunny: los votos positivos no son para el arma más rápida en el oeste, sino para las mejores respuestas. El tuyo es el mejor hasta ahora (solo mencioné iptables; en realidad proporcionaste la línea de comandos completa). La única cosa que el mío tiene la tuya no es la advertencia de que otros usuarios también pueden vincularse al puerto 8080. - CesarB
Tenga en cuenta que esto no funciona con IPv6. - Emmanuel Bourg
¿Alguien podría explicar cómo puedo eliminar esta regla más adelante cuando quiera? Después de ejecutarlo, funciona, pero aparentemente no es una "regla" porque no aparece cuando lo hago sudo iptables --list. Sé lo que es iptables y lo hace, pero nunca lo he usado antes de esto. - Encoderer
Gracias por su respuesta ... cada vez que reinicio Ubuntu, esta regla desaparece y tengo que ejecutarla nuevamente. ¿Hay una manera de guardarlo para siempre? - Coderji
@Coderji: verifique la sección "guardar" en la documentación de la comunidad: help.ubuntu.com/community/IptablesHowTo - Sunny


Utilizar Authbind.

Incluso funciona con Java si habilita la pila solo de IPv4 de Java. Yo suelo:

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

77
2017-11-14 13:12



Si el servidor es Tomcat, puede usar authbind automáticamente configurando AUTHBIND=yes en / etc / default / tomcat6 - Emmanuel Bourg
No pude hacer que esto funcionara en el servidor Ubuntu con el paquete Java predeterminado ... - Ashley Steel
Yo tampoco, ¿alguna solución conocida? - mark
Tenga en cuenta que debe configurar authbind para permitir realmente que esto suceda. De la página del manual: "/ etc / authbind / byport / port está probado. Si este archivo es accesible para que lo ejecute el usuario llamante, de acuerdo con el acceso (2), entonces se autoriza el enlace al puerto"., p.ej. para el puerto 80, sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80. La instalación inicial de authbind Generalmente no tiene autorizaciones preconfiguradas. - Jason C
¡Oh, nonononononono, nunca jamás hagas nada 777! - Johannes


Si su sistema lo admite, quizás pueda usar capacidades. Ver las capacidades del hombre, la que necesitas sería CAP_NET_BIND_SERVICE.

En Debian / Ubuntu más reciente puede ejecutar:

sudo apt-get install libcap2-bin 
sudo setcap 'cap_net_bind_service=+ep' /path/to/program

45
2018-05-30 20:32



esto funciona para nodejs: setcap 'cap_net_bind_service = + ep' / usr / bin / nodejs - JasonS
Esta. Me pregunto por qué esta respuesta no tiene más upvotes. Mucho más fácil que la opción iptables imho. - Dominik R
Esta es la respuesta correcta y más eficiente, todas las demás respuestas causan un impacto en el rendimiento o simplemente dudoso / inseguro. - OneOfOne


Otra solución es configurar su aplicación para que pueda enlazarse con el puerto 80. Como root, haga lo siguiente

chown root ./myapp
chmod +S ./myapp

Tenga en cuenta que al hacer esto, a menos que se haga del todo bien, lo expondrá a posibles agujeros de seguridad, ya que su aplicación hablará a la red y se ejecutará con todos los privilegios de root. Si toma esta solución, debe mirar el código fuente de Apache o Lighttpd o algo similar, donde usan los privilegios de la raíz para abrir el puerto, pero luego renuncie a esos privilegios y "conviértase" en un usuario con privilegios más bajos para que un secuestrador no puede hacerse cargo de toda su computadora.

Actualización: como se ve en esta preguntaParece que los kernels de Linux desde 2.6.24 tienen una nueva capacidad que le permite marcar un ejecutable (pero no un script, por supuesto) como "CAP_NET_BIND_SERVICE"capacidad. Si instala el paquete debian" libcap2-bin ", puede hacerlo emitiendo el comando

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

39
2017-11-10 14:44



Es lo mismo que ejecutarse como root, a menos que la aplicación sepa cómo eliminar privilegios. - CesarB
Esto es peligroso. Esto significa que cualquier solicitud se ejecutará como root. Es por una razón por la que incluso apache se inicia como raíz para enlazar, y luego deja los privilegios a otro usuario. - Sunny
Paul: el iptables no es tan peligroso, porque incluso si la aplicación está comprometida, no expondrá el sistema en ataques, al menos no con privilegios de root. Ejecutar la aplicación como root es otra historia. - Sunny
El peligro para iptables es solo si se trata de un sistema multiusuario, como dijo CesarB, ya que cualquiera puede enlazar a 8080 e interceptar el tráfico. - Sunny
lol, me encanta como la respuesta aceptada tiene un -15 - Evan Teran


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 impide que el usuario se conecte directamente al puerto 8080 en lugar de 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.

Usamos 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 redireccionaría a https://host:8181/. En este punto, estamos jodidos:

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

Yo uso 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 de RECHAZO predeterminada en la cadena de ENTRADA, este enfoque evita que los usuarios se conecten directamente a los puertos 8080, 8181


35
2018-02-20 16:19



Esto es bueno, pero ¿por qué no enlazar el demonio a localhost: 8080 en lugar de 0.0.0.0:8080? Quiero hacer eso, pero necesito las iptables para eso. - Amala
Funciona, realmente genial. - xtian


Simplemente uso Nginx al frente. Puede funcionar en localhost también.

  • apt-get install nginx

.. o ..

  • pkg_add -r nginx 

.. o lo que se adapte a tu sistema operativo.

Todo lo que necesita en nginx.conf, si se ejecuta en localhost, es:

servidor {
        escucha 80;
        server_name some.domain.org;
        ubicación / {
            proxy_set_header Host $ host;
            proxy_set_header X-Real-IP $ remote_addr;
            proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:8081;
        }
}

34
2017-11-20 14:30



Realmente me gusta esta solución. - thomasfedb
Esta es (una de) la solución sugerida por los mismos JFrog: jfrog.com/confluence/display/RTF/nginx - stolsvik


Tradicionalmente, en Unix, solo la raíz puede enlazar a puertos bajos (<1024).

La forma más sencilla de solucionar esto es ejecutar su servidor en una alto puerto (por ejemplo, 8080) y use una regla simple de iptables para reenviar las conexiones del puerto 80 al puerto 8080. Tenga en cuenta que con esto pierde la protección adicional de los puertos bajos; Cualquier usuario en su máquina puede enlazar al puerto 8080.


29
2017-11-10 14:36





Si su sistema lo admite, quizás pueda usar capacidades. Ver man capabilities, el que necesitas sería CAP_NET_BIND_SERVICE. No, nunca los he usado y no sé si realmente funcionan :-)


23
2017-11-10 16:27



funcionan, yo uso CAP_NET_RAW para ejecutar herramientas como tcpdump como un usuario normal. - Justin


Use un proxy inverso (nginx, apache + mod_proxy) o un proxy inverso de almacenamiento en caché (Squid, Varnish) frente a los servidores de su aplicación.

Con un proxy inverso puedes lograr muchas cosas interesantes como:

  • Balanceo de carga
  • Reinicie sus servidores de aplicaciones con usuarios que reciben una página de error elegante
  • Acelera las cosas con caché
  • Configuraciones detalladas que normalmente realiza con un proxy inverso y no con un servidor de aplicaciones

11
2017-10-18 15:36





Puedes usar el programa redir:

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1

6
2017-11-27 12:48