GNU/Linux >> Tutoriales Linux >  >> Linux

¿Permitir que el proceso no raíz se vincule a los puertos 80 y 443?

No estoy seguro de a qué se refieren las otras respuestas y comentarios aquí. Esto es posible con bastante facilidad. Hay dos opciones, ambas que permiten el acceso a puertos con números bajos sin tener que elevar el proceso a root:

Opción 1:Usar CAP_NET_BIND_SERVICE para otorgar acceso de puerto de número bajo a un proceso:

Con esto, puede otorgar acceso permanente a un binario específico para enlazar a puertos con números bajos a través del setcap comando:

sudo setcap CAP_NET_BIND_SERVICE=+eip /path/to/binary

Para obtener más detalles sobre la parte e/i/p, consulte cap_from_text .

Después de hacer esto, /path/to/binary podrá vincularse a puertos con números bajos. Tenga en cuenta que debe usar setcap en el propio binario en lugar de un enlace simbólico.

Opción 2:Usar authbind para otorgar acceso único, con un control más preciso de usuarios/grupos/puertos:

El authbind (página man) existe precisamente para esto.

  1. Instalar authbind utilizando su administrador de paquetes favorito.

  2. Configúrelo para otorgar acceso a los puertos relevantes, p. para permitir 80 y 443 de todos los usuarios y grupos:

    sudo touch /etc/authbind/byport/80
    sudo touch /etc/authbind/byport/443
    sudo chmod 777 /etc/authbind/byport/80
    sudo chmod 777 /etc/authbind/byport/443
    
  3. Ahora ejecuta tu comando a través de authbind (opcionalmente especificando --deep u otros argumentos, consulte la página del manual):

    authbind --deep /path/to/binary command line args
    

    Por ejemplo

    authbind --deep java -jar SomeServer.jar
    

Hay ventajas y desventajas para los dos anteriores. La opción 1 otorga confianza al binario pero no proporciona ningún control sobre el acceso por puerto. La opción 2 otorga confianza al usuario/grupo y proporciona control sobre el acceso por puerto, pero las versiones anteriores solo admitían IPv4 (ya que originalmente escribí esto, se lanzaron versiones más nuevas con compatibilidad con IPv6).


Dale Hagglund está en el clavo. Así que solo voy a decir lo mismo pero de una manera diferente, con algunos detalles y ejemplos. ☺

Lo correcto en los mundos de Unix y Linux es:

  • tener un programa pequeño, simple y fácilmente auditable que se ejecute como superusuario y enlace el socket de escucha;
  • tener otro programa pequeño, simple, fácilmente auditable que elimine privilegios, generado por el primer programa;
  • tener la carne del servicio, en un tercero separado ejecutar bajo una cuenta que no sea de superusuario y la cadena cargada por el segundo programa, esperando simplemente heredar un descriptor de archivo abierto para el socket.

Tienes una idea equivocada de dónde está el alto riesgo. El alto riesgo está en leer de la red y actuar sobre lo que se lee no en los simples actos de abrir un socket, vincularlo a un puerto y llamar a listen() . Es la parte de un servicio que hace la comunicación real que es de alto riesgo. Las partes que se abren, bind() y listen() , e incluso (hasta cierto punto) la parte que accepts() , no son de alto riesgo y se pueden ejecutar bajo la égida del superusuario. No usan ni actúan (con la excepción de las direcciones IP de origen en el accept() caso) datos que están bajo el control de extraños no confiables a través de la red.

Hay muchas maneras de hacer esto.

inetd

Como dice Dale Hagglund, el antiguo "superservidor de red" inetd Haz esto. La cuenta bajo la cual se ejecuta el proceso de servicio es una de las columnas en inetd.conf . No separa la parte de escucha y la parte de eliminación de privilegios en dos programas separados, pequeños y fácilmente auditables, pero separa el código del servicio principal en un programa separado, exec() editado en un proceso de servicio que genera con un descriptor de archivo abierto para el socket.

La dificultad de auditar no es un gran problema, ya que uno solo tiene que auditar un programa. inetd El principal problema de no es auditar tanto, sino que no proporciona un control de servicio de tiempo de ejecución simple y detallado, en comparación con las herramientas más recientes.

UCSPI-TCP y daemontools

Los paquetes UCSPI-TCP y daemontools de Daniel J. Bernstein fueron diseñados para hacer esto en conjunto. También se puede utilizar el conjunto de herramientas daemontools-encore de Bruce Guenter, en gran parte equivalente.

El programa para abrir el descriptor de archivo de socket y enlazar con el puerto local privilegiado es tcpserver , de UCSPI-TCP. Hace tanto el listen() y el accept() .

tcpserver luego genera un programa de servicio que elimina los privilegios de root (porque el protocolo que se sirve implica comenzar como superusuario y luego "iniciar sesión", como es el caso, por ejemplo, con un demonio FTP o SSH) o setuidgid que es un programa autónomo pequeño y fácilmente auditable que solo elimina privilegios y luego encadena cargas al programa de servicio propiamente dicho (ninguna parte del cual se ejecuta con privilegios de superusuario, como es el caso de, digamos, qmail-smtpd ).

Un servicio run el script sería, por ejemplo, (este para dummyidentd para proporcionar un servicio IDENT nulo):

#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl

comer

Mi paquete nosh está diseñado para hacer esto. Tiene un pequeño setuidgid utilidad, al igual que los demás. Una pequeña diferencia es que se puede usar con systemd -estilo de servicios "LISTEN_FDS" así como con servicios UCSPI-TCP, por lo que el tradicional tcpserver el programa es reemplazado por dos programas separados:tcp-socket-listen y tcp-socket-accept .

Nuevamente, las utilidades de un solo propósito se generan y se cargan en cadena entre sí. Una peculiaridad interesante del diseño es que uno puede eliminar los privilegios de superusuario después de listen() pero antes incluso accept() . Aquí hay un run secuencia de comandos para qmail-smtpd que de hecho hace exactamente eso:

#!/bin/nosh
fdmove -c 2 1
clearenv --keep-path --keep-locale
envdir env/
softlimit -m 70000000
tcp-socket-listen --combine4and6 --backlog 2 ::0 smtp
setuidgid qmaild
sh -c 'exec \
tcp-socket-accept -v -l "${LOCAL:-0}" -c "${MAXSMTPD:-1}" \
ucspi-socket-rules-check \
qmail-smtpd \
'

Los programas que se ejecutan bajo la égida del superusuario son las pequeñas herramientas de carga en cadena independientes del servicio fdmove , clearenv , envdir , softlimit , tcp-socket-listen y setuidgid . Por el punto que sh se inicia, el socket está abierto y vinculado al smtp puerto, y el proceso ya no tiene privilegios de superusuario.

s6, s6-redes y execline

Los paquetes de red s6 y s6 de Laurent Bercot fueron diseñados para hacer esto en conjunto. Los comandos son estructuralmente muy similares a los de daemontools y UCSPI-TCP.

run los scripts serían muy parecidos, excepto por la sustitución de s6-tcpserver para tcpserver y s6-setuidgid para setuidgid . Sin embargo, también se puede optar por hacer uso del conjunto de herramientas execline de M. Bercot al mismo tiempo.

Aquí hay un ejemplo de un servicio FTP, ligeramente modificado del original de Wayne Marshall, que usa execline, s6, s6-networking y el programa de servidor FTP de publicfile:

#!/command/execlineb -PW
multisubstitute {
    define CONLIMIT 41
    define FTP_ARCHIVE "/var/public/ftp"
}
fdmove -c 2 1
s6-envuidgid pubftp 
s6-softlimit -o25 -d250000 
s6-tcpserver -vDRH -l0 -b50 -c ${CONLIMIT} -B '220 Features: a p .' 0 21 
ftpd ${FTP_ARCHIVE}

ipsvd

ipsvd de Gerrit Pape es otro conjunto de herramientas que se ejecuta en la misma línea que ucspi-tcp y s6-networking. Las herramientas son chpst y tcpsvd esta vez, pero hacen lo mismo, y el código de alto riesgo que lee, procesa y escribe cosas enviadas a través de la red por clientes que no son de confianza todavía está en un programa separado.

Aquí está el ejemplo de M. Pape de ejecutar fnord en un run guión:

#!/bin/sh
exec 2>&1
cd /public/10.0.5.4
exec \
chpst -m300000 -Uwwwuser \
tcpsvd -v 10.0.5.4 443 sslio -v -unobody -//etc/fnord/jail -C./cert.pem \
fnord

systemd

systemd , el nuevo sistema de supervisión e inicio de servicios que se puede encontrar en algunas distribuciones de Linux, pretende hacer lo que inetd puede hacer. Sin embargo, no utiliza un conjunto de pequeños programas autónomos. Uno tiene que auditar systemd en su totalidad, por desgracia.

Con systemd uno crea archivos de configuración para definir un socket que systemd escucha y un servicio que systemd empieza. El archivo de "unidad" del servicio tiene configuraciones que permiten un gran control sobre el proceso del servicio, incluido el usuario con el que se ejecuta.

Con ese usuario configurado como no superusuario, systemd hace todo el trabajo de abrir el socket, vincularlo a un puerto y llamar a listen() (y, si es necesario, accept() ) en el proceso #1 como superusuario, y el proceso de servicio que genera se ejecuta sin privilegios de superusuario.


Tengo un enfoque bastante diferente. Quería usar el puerto 80 para un servidor node.js. No pude hacerlo porque se instaló Node.js para un usuario que no es sudo. Traté de usar enlaces simbólicos, pero no funcionó para mí.

Luego me di cuenta de que puedo reenviar conexiones de un puerto a otro puerto. Así que inicié el servidor en el puerto 3000 y configuré un reenvío de puerto desde el puerto 80 al puerto 3000.

Este enlace proporciona los comandos reales que se pueden usar para hacer esto. Aquí están los comandos:

host local/bucle invertido

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

externo

sudo iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 3000

He usado el segundo comando y funcionó para mí. Así que creo que este es un término medio para no permitir que el proceso de usuario acceda a los puertos inferiores directamente, sino darles acceso mediante el reenvío de puertos.


Linux
  1. Cómo abrir los puertos 80 y 443 en FirewallD

  2. Instale SoftHSM y acceda a él a través del programa Java

  3. Ssh:¿cómo rechazar un proceso en ejecución y asociarlo a un nuevo shell de pantalla?

  4. ¿Por qué Cd no es un programa?

  5. Linux – ¿Bloquear el acceso a la red de un proceso?

Ubuntu 22.04 abre el puerto HTTP 80 y el puerto HTTPS 443 con ufw

Cómo encontrar el ID de proceso de un programa y eliminarlo [Consejo rápido]

¿Cómo permitir o bloquear el puerto y la dirección IP usando Firewalld, tablas de IP y UFW en Linux?

Cómo escribir y ejecutar un programa C en Linux

UNIX/Linux:Cómo crontab valida el acceso basado en los archivos cron.allow y cron.deny

Evitar que otras aplicaciones se vinculen a los puertos 80 y 443