¿Existe alguna forma de que los procesos no root se vinculen a puertos "privilegiados" en Linux?
Es muy molesto tener esta limitación en mi caja de desarrollo, cuando nunca habrá más usuarios que yo.
Conozco las soluciones estándar , pero ninguna hace exactamente lo que quiero:
- authbind (La versión en pruebas de Debian, 1.0, solo admite IPv4)
- Uso del objetivo REDIRECT de iptables para redirigir un puerto bajo a un puerto alto (la tabla "nat" aún no está implementada para ip6tables, la versión IPv6 de iptables)
- sudo (Ejecutar como root es lo que intento evitar)
- SELinux (o similar). (Este es solo mi cuadro de desarrollo, no quiero introducir mucha complejidad adicional).
¿Existe alguna sysctl
variable simple que permita que procesos no root se vinculen a puertos "privilegiados" (puertos menores que 1024) en Linux, o simplemente no tengo suerte?
EDITAR: en algunos casos, puede utilizar capacidades para hacer esto.
Bien, gracias a las personas que señalaron el sistema de capacidades y CAP_NET_BIND_SERVICE
la capacidad. Si tiene un kernel reciente, es posible usarlo para iniciar un servicio como no root pero vincular puertos bajos. La respuesta corta es que sí:
setcap 'cap_net_bind_service=+ep' /path/to/program
Y luego, en cualquier momento program
que se ejecute a partir de entonces, tendrá la CAP_NET_BIND_SERVICE
capacidad. setcap
está en el paquete debian libcap2-bin
.
Ahora las advertencias:
- Necesitará al menos un kernel 2.6.24
- Esto no funcionará si su archivo es un script. (es decir, utiliza una
#!
línea para iniciar un intérprete). En este caso, hasta donde tengo entendido, habría que aplicar la capacidad al ejecutable del intérprete, lo que por supuesto es una pesadilla de seguridad, ya que cualquier programa que use ese intérprete tendrá la capacidad. No pude encontrar ninguna manera limpia y fácil de solucionar este problema. - Linux se desactivará
LD_LIBRARY_PATH
en cualquieraprogram
que tenga privilegios elevados comosetcap
osuid
. Entonces, siprogram
usa el suyo propio.../lib/
, es posible que deba buscar otra opción, como el reenvío de puertos.
Recursos:
- capacidades(7) página de manual . Lea esto detenidamente si va a utilizar capacidades en un entorno de producción. Hay algunos detalles realmente complicados sobre cómo se heredan las capacidades a través de llamadas exec() que se detallan aquí.
- página de manual de setcap
- "Vincular puertos por debajo de 1024 sin root en GNU/Linux" : el documento que me indicó por primera vez
setcap
.
Nota: RHEL agregó esto por primera vez en v6 .
Actualización 2017:
Usar enlace de autenticación
Descargo de responsabilidad (actualización para 2021): tenga en cuenta que authbind
funciona a través de LD_PRELOAD
, que solo se usa si su programa usa libc
, lo cual no es (o podría) no ser el caso si su programa está compilado con GO o cualquier otro compilador que evite C. Si usa Vaya, configure el parámetro del kernel para el rango de puertos protegidos, consulte la parte inferior de la publicación. </EndUpdate>
Authbind
es mucho mejor que CAP_NET_BIND_SERVICE
un kernel personalizado.
CAP_NET_BIND_SERVICE
otorga confianza al binario pero no proporciona control sobre el acceso por puerto.Authbind
otorga confianza al usuario/grupo y proporciona control sobre el acceso por puerto, y admite tanto IPv4 como IPv6 ( últimamente se ha agregado compatibilidad con IPv6 ).
Instalar:
apt-get install authbind
Configure el acceso a los puertos relevantes, por ejemplo, 80 y 443 para 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/443Ejecute su comando mediante
authbind
(opcionalmente especificando--deep
u otros argumentos, consulteman authbind
):authbind --deep /path/to/binary command line args e.g. authbind --deep java -jar SomeServer.jar
Como seguimiento de la fabulosa recomendación de Joshua (=no recomendada a menos que sepas lo que haces) para hackear el kernel:
Lo publiqué aquí por primera vez .
Simple. Con un kernel normal o viejo, no es así.
Como han señalado otros, iptables
se puede reenviar un puerto.
Como también lo han señalado otros, CAP_NET_BIND_SERVICE
también puede hacer el trabajo.
Por supuesto CAP_NET_BIND_SERVICE
, fallará si inicia su programa desde un script, a menos que establezca el límite en el intérprete de shell, lo cual no tiene sentido, también podría ejecutar su servicio como root...
por ejemplo, para Java, debe aplicarlo a la JVM JAVA
sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java
Obviamente, eso significa que cualquier programa Java puede vincular puertos del sistema.
Lo mismo ocurre con mono/.NET.
También estoy bastante seguro de que xinetd no es la mejor idea.
Pero dado que ambos métodos son trucos, ¿por qué no simplemente eliminar el límite eliminando la restricción?
Nadie dijo que tengas que ejecutar un kernel normal, así que puedes ejecutar el tuyo propio.
Simplemente descargue la fuente del kernel más reciente (o el mismo que tiene actualmente). Después vas a:
/usr/src/linux-<version_number>/include/net/sock.h:
Ahí buscas esta línea
/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK 1024
y cambiarlo a:
#define PROT_SOCK 0
Si no desea tener una situación ssh insegura, cámbiela a esto:
#define PROT_SOCK 24
Generalmente, usaría la configuración más baja que necesite, por ejemplo, 79 para http o 24 cuando use SMTP en el puerto 25.
Eso ya es todo.
Compile el kernel e instálelo.
Reiniciar.
Terminado: ese estúpido límite desapareció, y eso también funciona para los scripts.
Así es como se compila un kernel:
https://help.ubuntu.com/community/Kernel/Compile
# You can get the kernel-source via package `linux-source`, no manual download required
apt-get install linux-source fakeroot
mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>
# Apply the changes to PROT_SOCK define in /include/net/sock.h
# Copy the kernel config file you are currently using
cp -vi /boot/config-`uname -r` .config
# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev
# Run menuconfig (optional)
make menuconfig
# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers
# And wait a long long time
cd ..
En una palabra:
- Úsalo
iptables
si quieres mantenerte seguro, - compila el kernel si quieres estar seguro de que esta restricción nunca más te molestará.
método syctl
Nota:
Últimamente ya no es necesario actualizar el kernel.
Ahora puedes configurar:
sysctl net.ipv4.ip_unprivileged_port_start=80
O persistir:
sysctl -w net.ipv4.ip_unprivileged_port_start=80
Y si eso produce un error, simplemente edite /etc/sysctl.conf
con nano y configure el parámetro allí para persistencia durante los reinicios.
o víaprocfs
echo 80 | sudo tee /proc/sys/net/ipv4/ip_unprivileged_port_start
Puedes hacer una redirección de puerto. Esto es lo que hago para un servidor de políticas Silverlight que se ejecuta en una máquina Linux
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300
Por alguna razón, nadie menciona la posibilidad de reducir sysctl net.ipv4.ip_unprivileged_port_start al valor que necesita. Ejemplo: Necesitamos vincular nuestra aplicación al puerto 443.
sysctl net.ipv4.ip_unprivileged_port_start=443
Algunos pueden decir que existe un posible problema de seguridad: los usuarios sin privilegios ahora pueden conectarse a otros puertos privilegiados (444-1024). Pero puedes resolver este problema fácilmente con iptables, bloqueando otros puertos:
iptables -I INPUT -p tcp --dport 444:1024 -j DROP
iptables -I INPUT -p udp --dport 444:1024 -j DROP
Comparación con otros métodos. Este método:
- desde algún punto es (en mi opinión) incluso más seguro que configurar CAP_NET_BIND_SERVICE/setuid, ya que una aplicación no establece ningún setuid, ni siquiera en parte (las capacidades en realidad lo son). Por ejemplo, para detectar un coredump de una aplicación con capacidad habilitada, necesitará cambiar sysctl fs.suid_dumpable (lo que conduce a otros posibles problemas de seguridad). Además, cuando CAP/suid está configurado, el directorio /proc/PID es propiedad de root, por lo que su usuario no root no tendrá información/control completo del proceso en ejecución, por ejemplo, el usuario no podrá (en casos comunes) determinar qué conexiones pertenecen a la aplicación a través de /proc/PID/fd/ (netstat -aptn | grep PID).
- tiene una desventaja de seguridad: mientras su aplicación (o cualquier aplicación que use los puertos 443-1024) no funciona por algún motivo, otra aplicación podría tomar el puerto. Pero este problema también podría aplicarse a CAP/suid (en caso de que lo configure en el intérprete, por ejemplo, java/nodejs) e iptables-redirect. Utilice el método systemd-socket para excluir este problema. Utilice el método authbind para permitir únicamente la vinculación de usuarios especiales.
- no requiere configurar CAP/suid cada vez que implementa una nueva versión de la aplicación.
- no requiere soporte/modificación de la aplicación, como el método systemd-socket.
- no requiere reconstrucción del kernel (si la versión en ejecución admite esta configuración de sysctl)
- no hace LD_PRELOAD como el método authbind/privbind, esto podría afectar potencialmente el rendimiento, la seguridad y el comportamiento (¿lo hace? No lo he probado). En el resto, authbind es un método realmente flexible y seguro.
- supera el método REDIRECT/DNAT de iptables, ya que no requiere traducción de direcciones, seguimiento del estado de la conexión, etc. Esto solo se nota en sistemas de alta carga.
Dependiendo de la situación, elegiría entre sysctl, CAP, authbind e iptables-redirect. Y es genial que tengamos tantas opciones.