Permitir que un usuario permita escuchar un puerto por debajo de 1024

63

Necesito permitir que un usuario (diferente del root) ejecute un servidor que escucha en el puerto 80.

¿Hay alguna forma de hacer esto?

peoro
fuente
1
Esta pregunta está abierta a interpretación. Espero que signifique "ha creado un nuevo servicio del sistema que (como root) le gustaría ejecutar en una cuenta no privilegiada por razones de seguridad" (se considera una buena práctica) y no "Tengo un usuario al que se le preguntó si puede ejecutar su propio servidor web en mi sistema, ¿cómo les permito el acceso? " (considerada una práctica bastante pobre)
Michael Shaw
3
@Ptolomeo, la razón real es: mi máquina está detrás de un firewall que bloquea cualquier puerto que no sea el 80. Quiero alojar un servidor (que no elimina los privilegios), por lo tanto, necesito que escuche en el puerto 80, pero no No confíe en que se ejecute como root (por razones obvias de seguridad). Tengo permitido hacer esto, si te importa.
peoro
serverfault.com/questions/112795/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Respuestas:

50

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

Esto funcionará para procesos específicos. Pero para permitir que un usuario en particular se vincule a puertos inferiores a 1024, deberá agregarlo a los sudoers.

Echa un vistazo a esta discusión para más información.

Rohan Monga
fuente
31

(Algunos de estos métodos se han mencionado en otras respuestas; estoy dando varias opciones posibles en un orden aproximado de preferencia).

Puede redirigir el puerto bajo a un puerto alto y escuchar en el puerto alto.

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 1080

Puede iniciar su servidor como privilegios de root y soltar después de que haya comenzado a escuchar en el puerto privilegiado. Preferiblemente, en lugar de codificarlo usted mismo, inicie su servidor desde un contenedor que haga el trabajo por usted. Si su servidor inicia una instancia por conexión, inicie desde inetd(o un programa similar como xinetd). Para inetd, use una línea como esta en /etc/inetd.conf:

http  stream  tcp  nowait  username:groupname  /path/to/server/executable  argv[0] argv[1]…

Si su servidor escucha en una sola instancia, inícielo desde un programa como authbind. Cree un archivo vacío /etc/authbind/byport/80y hágalo ejecutable para el usuario que ejecuta el servidor; o crear /etc/authbind/byuid/1234, donde 1234 es el UID que ejecuta el servidor, que contiene la línea 0.0.0.0/0:80,80.

Si el archivo ejecutable de su servidor está almacenado en un sistema de archivos que admite capacidades, puede darle la capacidad . Tenga en cuenta que las capacidades aún son relativamente nuevas y todavía tienen algunos problemas .cap_net_bind_service

setcap cap_net_bind_service=ep /path/to/server/executable
Gilles 'SO- deja de ser malvado'
fuente
44
En todos los casos con los que tuve que lidiar, el ejecutable era un script que lanzaba Java o Python. Como un hombre sin 10 horas para gastar en los puntos finos, su solución de iptables lo cubre sin problemas.
srking
Para la solución de iptables, también tuve que agregar una regla de filtro, ya -A INPUT -p tcp --dport 1080 -j ACCEPTque de lo contrario no funcionaría (también tengo un -j DROPcomodín). Así que me quedan dos tomas de escucha.
thom_nic
4

La respuesta corta es que esto no es posible por diseño.

La respuesta larga es que en los mundos de código abierto hay muchas personas que juegan con el diseño y proponen métodos alternativos. En general, es una práctica ampliamente aceptada que esto no debería ser posible. El hecho de que lo esté intentando probablemente significa que tiene otra falla de diseño en su sistema y debe reconsiderar la arquitectura de todo el sistema a la luz de las mejores prácticas * nix y las implicaciones de seguridad.

Dicho esto, un programa para autorizar el acceso no root a puertos bajos es authbind . Tanto selinux como grsecurity también proporcionan marcos para esas autenticaciones afinadas.

Por último, si desea que usuarios específicos ejecuten programas específicos como root y lo que realmente necesita es permitir que un usuario reinicie apache o algo así, ¡ sudoes su amigo!

Caleb
fuente
8
La "seguridad" portuaria realmente no te da mucho en el mundo moderno.
pjc50
3
@ pjc50: Sí, lo hace. Se trata de confianza implícita. Los números de puerto bajos implican una alta confianza. Se espera que SSH, POP, FTP y otros demonios soliciten contraseñas de nivel de sistema y otras credenciales cuando se abren sus puertos. Si a los usuarios se les permitiera escuchar en puertos bajos en una caja, podrían iniciar demonios falsos en puertos no utilizados (o bloqueados) y obtener contraseñas de usuarios desprevenidos. Esas contraseñas podrían usarse en ese cuadro para comprometer otras cuentas, incluida la raíz.
Caleb
8
Esa es una forma de seguridad bastante débil. Si se ha conectado a algo y no ha realizado una transacción de certificado, entonces no tiene idea de con quién está hablando, es decir, ataques MITM.
pjc50
55
Supongo que lo que se necesita es chown para los puertos: entonces podría "chown mail port25" y luego (a) su demonio de correo no necesita iniciarse con privs raíz y (b) nadie más puede secuestrarlo.
pjc50
77
Si bien esto puede haber sido cierto "por diseño" cuando Linux estaba en su infancia, tiene muy poco sentido en ese momento y ahora. La seguridad se trata de lo que un usuario puede y no puede hacer. Permitir que solo el usuario root use el puerto 80, por ejemplo, es un gran riesgo de seguridad, porque significa que debe otorgar acceso root a las personas que necesitan usar el puerto 80 pero no deberían tener acceso root. Si confía en que el usuario no root X usa el puerto 80, debería poder codificar esa confianza en su sistema operativo. Afortunadamente, como usted mencionó, hay soluciones desagradables que permiten esto, como authbind.
BT
3

Puede usar el reenvío de puertos netcat o xinetd o iptables, o usar apache como proxy front-end y ejecutar el proceso en un puerto no privilegiado.

jamespo
fuente
3

Authbind , @Gilles ya lo mencionó, pero me gustaría ampliarlo un poco.

Tiene un conveniente control de acceso (detalles en la página del manual): puede filtrar el acceso por puerto, dirección de interfaz, uid, rangos de dirección o puerto y la combinación de estos.

Tiene un parámetro muy útil --depth:

- niveles de profundidad

Hace que authbind afecte a los programas que están en niveles profundos en el gráfico de llamada. El valor predeterminado es 1.

"Niveles profundos" significa que cuando un script (o programa) ejecuta otro script desciende un nivel. Entonces, si lo tiene --depth 5significa en los niveles 1 (¿o es 0?) A 5, tiene permiso para vincular, mientras que en el nivel 6 y más, no lo tiene. Útil cuando desea que un script tenga acceso, pero no programas que se ejecutan con o sin su conocimiento.


Para ilustrar, podría tener algo como esto: por razones de seguridad, tiene un usuario javadestinado a ejecutar solo Java y desea darle acceso al puerto 80:

echo > /etc/authbind/byport/80
chown root:java /etc/authbind/byport/80
chmod 710 /etc/authbind/byport/80

Lo creé ../byport/80 file, se lo di al javagrupo de usuarios (cada usuario tiene su propio grupo) y lo hice ejecutable por grupo, lo que significa que es ejecutable por javausuario. Si está dando acceso por puerto, el archivo debe ser ejecutable por el usuario que debería tener acceso, así que lo hicimos.

Esto podría ser suficiente para el Joe promedio, pero debido a que sabe cómo usar el --depthparámetro, corre (como javausuario) authbind --depth [depth] my_web_app's_start_scriptcomenzando --depth 1y avanzando hasta encontrar la profundidad más pequeña que funciona y la usa.

Lea la página del manual para más detalles .

Dominykas Mostauskis
fuente
1

Intenté el método iptables PREROUTING REDIRECT, pero descubrí que también afecta los paquetes reenviados. Es decir, si la máquina también reenvía paquetes entre interfaces (por ejemplo, si actúa como un punto de acceso Wi-Fi conectado a una red Ethernet), entonces la regla de iptables también detectará las conexiones de los clientes conectados a los destinos de Internet y los redirigirá a la máquina. Eso no era lo que quería: solo quería redirigir las conexiones que se dirigían a la máquina misma.

Una posibilidad es utilizar el reenvío de puertos TCP. Por ejemplo, usando socat:

socat TCP4-LISTEN:www,reuseaddr,fork TCP4:localhost:8080

Sin embargo, una desventaja de ese método es que la aplicación que está escuchando en el puerto 8080 no conoce la dirección de origen de las conexiones entrantes (por ejemplo, para el registro u otros fines de identificación).

Craig McQueen
fuente