在linux上,有没有办法让非根进程绑定到“特权”端口?

fbcarpbf  于 2021-10-10  发布在  Java
关注(0)|答案(10)|浏览(264)

当除了我之外再也没有其他用户的时候,在我的开发框上有这样的限制是非常烦人的。
我知道标准的解决办法,但没有一个能完全满足我的要求:
authbind(debian测试中的版本,1.0,仅支持ipv4)
使用iptables重定向目标将低端口重定向到高端口(尚未为ip6tables(iptables的ipv6版本)实现“nat”表)
sudo(以root身份运行是我试图避免的)
selinux(或类似产品)(这只是我的开发工具,我不想引入太多额外的复杂性。)
有什么简单的方法吗 sysctl 变量,允许非根进程绑定到linux上的“特权”端口(小于1024个端口),还是我运气不好?
编辑:在某些情况下,您可以使用功能来执行此操作。

f8rj6qna

f8rj6qna1#

好的,感谢那些指出系统功能的人 CAP_NET_BIND_SERVICE 能力。如果您有一个最近的内核,那么确实可以使用它以非根端口但绑定低端口的形式启动服务。简单的回答是,你做到了:

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

然后随时 program 之后执行,它将具有 CAP_NET_BIND_SERVICE 能力。 setcap 在debian包中 libcap2-bin .
现在要注意的是:
您至少需要一个2.6.24内核
如果您的文件是脚本,则此操作无效(例如,使用#!行以启动解释器)。在这种情况下,据我所知,您必须将该功能应用于解释器可执行文件本身,这当然是一个安全噩梦,因为任何使用该解释器的程序都将具有该功能。我找不到任何干净、简单的方法来解决这个问题。
linux将在任何服务器上禁用ld_library_路径 program 它具有提升的特权,比如 setcapsuid . 所以如果你的 program 使用自己的 .../lib/ ,您可能需要研究另一个选项,如端口转发。
资源:
功能(7)手册页。如果要在生产环境中使用功能,请仔细阅读本文。关于如何在exec()调用中继承功能,这里有一些非常棘手的细节。
setcap手册页
“在gnu/linux上无根绑定1024以下的端口”:这篇文档首先向我指出 setcap .
注意:rhel首先在v6中添加了此功能。

lb3vh1jj

lb3vh1jj2#

您可以执行端口重定向。这就是我为运行在linux机器上的silverlight策略服务器所做的

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300
uxhixvfz

uxhixvfz3#

标准的方法是将它们设置为“setuid”,以便它们以root身份启动,然后在它们绑定到端口但开始接受到该端口的连接之前,就放弃root权限。您可以在apache和inn的源代码中看到这方面的好例子。我听说lighttpd是另一个很好的例子。
另一个例子是postfix,它使用多个通过管道进行通信的守护进程,其中只有一个或两个(除了接受或发出字节外几乎没有其他功能)作为根运行,其余的以较低的权限运行。

0dxa2lsx

0dxa2lsx4#

或者修补内核并删除检查。
(最后选择,不推荐)。
在里面 net/ipv4/af_inet.c ,删除两行内容为

if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
              goto out;

内核将不再检查特权端口。

vhmi4jdf

vhmi4jdf5#

2017年更新:

使用authbind

比cap_net_bind_服务或定制内核要好得多。
cap_net_bind_服务向二进制文件授予信任,但不提供对每个端口访问的控制。
authbind向用户/组授予信任,并提供对每个端口访问的控制,同时支持ipv4和ipv6(最近已添加ipv6支持)。
安装: apt-get install authbind 为所有用户和组配置对相关端口的访问,例如80和443:
sudotouch/etc/authbind/byport/80
sudotouch/etc/authbind/byport/443
sudo chmod 777/etc/authbind/byport/80
sudo chmod 777/etc/authbind/byport/443
通过以下方式执行您的命令: authbind (可选地指定 --deep 或其他参数,请参见手册页):

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

例如

authbind --deep java -jar SomeServer.jar

作为joshua关于破解内核的绝妙建议(=除非您知道自己在做什么,否则不推荐)的后续建议:
我先把它贴在这里。
简单。对于普通内核或旧内核,您不需要。
正如其他人指出的,iptables可以转发端口。
正如其他人所指出的,cap_net_bind_服务也可以完成这项工作。
当然,如果您从脚本启动程序,cap_net_bind_服务将失败,除非您在shell解释器上设置cap,这是毫无意义的,您也可以作为root用户运行服务。。。
e、 对于java,您必须将其应用于java jvm

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java

显然,这意味着任何java程序都可以绑定系统端口。
mono/.net的dito。
我也很确定xinetd不是最好的主意。
但既然这两种方法都是黑客,为什么不通过解除限制来解除限制呢?
没有人说你必须运行一个普通的内核,所以你可以自己运行。
您只需下载最新内核的源代码(或与当前相同的内核)。之后,您可以访问:

/usr/src/linux-<version_number>/include/net/sock.h:

你看这条线

/* Sockets 0-1023 can't be bound to unless you are superuser */

# define PROT_SOCK       1024

并将其更改为


# define PROT_SOCK 0

如果不希望出现不安全的ssh情况,可以将其更改为:#define prot_sock 24
通常,我会使用您需要的最低设置,例如http为79,在端口25上使用smtp时为24。
就这些了。
编译内核并安装它。
重新启动。
完成-这个愚蠢的限制消失了,这也适用于脚本。
下面是编译内核的方法:
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 ..

简言之,如果您想保持安全,请使用iptables;如果您想确保此限制不再困扰您,请编译内核。

vddsk6oq

vddsk6oq6#

出于某种原因,没有人提到将sysctl net.ipv4.ip_unprivileged_port_start降低到您需要的值。示例:我们需要将应用程序绑定到443端口。

sysctl net.ipv4.ip_unprivileged_port_start=443

有人可能会说,存在一个潜在的安全问题:非特权用户现在可能会绑定到其他特权端口(444-1024)。但是,通过阻止其他端口,您可以使用iptables轻松解决此问题:

iptables -I INPUT -p tcp --dport 444:1024 -j DROP
iptables -I INPUT -p udp --dport 444:1024 -j DROP

与其他方法的比较。此方法:
从某种意义上讲,它(imo)甚至比设置cap_net_bind_service/setuid更安全,因为应用程序根本不需要setuid,甚至部分不需要setuid(功能实际上是)。例如,要捕获支持功能的应用程序的coredump,您还需要更改sysctl fs.suid_dumpable(这会导致另一个潜在的安全问题),当设置cap/suid时,/proc/pid目录由root所有,因此您的非root用户将无法获得运行进程的全部信息/控制权,例如,用户将无法(在常见情况下)通过/proc/pid/fd/(netstat-aptn | grep-pid)确定哪些连接属于应用程序。
存在安全缺陷:当您的应用程序(或任何使用端口443-1024的应用程序)因某种原因关闭时,另一个应用程序可能会占用该端口。但这个问题也可以应用于cap/suid(如果您在解释器上设置它,例如java/nodejs)和iptables重定向。使用systemd套接字方法排除此问题。使用authbind方法仅允许特殊用户绑定。
不需要每次部署新版本的应用程序时都设置cap/suid。
不需要应用程序支持/修改,如systemd套接字方法。
不需要内核重建(如果运行的版本支持此sysctl设置)
不像authbind/privbind方法那样进行ld_预加载,这可能会影响性能、安全性和行为(是吗?还没有测试)。在rest中,authbind是一种非常灵活和安全的方法。
过度执行iptables redirect/dnat方法,因为它不需要地址转换、连接状态跟踪等。这仅在高负载系统上才明显。
根据情况,我将在sysctl、cap、authbind和iptables重定向之间进行选择。这是伟大的,我们有这么多的选择。

uqxowvwt

uqxowvwt7#

您可以设置本地ssh隧道,例如,如果希望端口80访问绑定到3000的应用程序:

sudo ssh $USERNAME@localhost -L 80:localhost:3000 -N

这具有使用脚本服务器的优点,而且非常简单。

amrnrhlw

amrnrhlw8#

文件功能并不理想,因为它们在包更新后可能会中断。
理想的解决方案imho应该是能够创建具有可继承性的shell CAP_NET_BIND_SERVICE 设置
下面是一个有点复杂的方法:

sg $DAEMONUSER "capsh --keep=1 --uid=`id -u $DAEMONUSER` \
     --caps='cap_net_bind_service+pei' -- \
     YOUR_COMMAND_GOES_HERE"
``` `capsh` 该实用程序可以在debian/ubuntu发行版的libcap2 bin包中找到。事情是这样的: `sg` 将有效组id更改为守护程序用户的有效组id。这是必要的,因为 `capsh` 保持gid不变,我们绝对不想要它。
设置位“更改uid时保持功能”。
将uid更改为 `$DAEMONUSER` 放下所有盖子(此时所有盖子仍然存在,因为 `--keep=1` ),可继承的除外 `cap_net_bind_service` 执行命令(“--”是分隔符)
结果是具有指定用户和组的进程,以及 `cap_net_bind_service` 特权。
例如,从 `ejabberd` 启动脚本:

sg $EJABBERDUSER "capsh --keep=1 --uid=id -u $EJABBERDUSER --caps='cap_net_bind_service+pei' -- $EJABBERD --noshell -detached"

rseugnpd

rseugnpd9#

现代linux支持 /sbin/sysctl -w net.ipv4.ip_unprivileged_port_start=0 .

ev7lccsx

ev7lccsx10#

我知道这是一个老问题,但现在有了最近的(>=4.3)内核,终于有了一个很好的答案-环境功能。
快速的答案是从git中获取最新(尚未发布)版本的libcap副本并编译它。复制结果 progs/capsh 某处二进制( /usr/local/bin 是一个不错的选择)。然后,作为root用户,用

/usr/local/bin/capsh --keep=1 --user='your-service-user-name' \
    --inh='cap_net_bind_service' --addamb='cap_net_bind_service' \ 
    -- -c 'your-program'

按顺序,我们是
声明当我们切换用户时,我们希望保留当前的功能集
将用户和组切换到“您的服务用户名”
添加 cap_net_bind_service 对继承集和环境集的功能
分叉 bash -c 'your-command' (自 capsh 使用后面的参数自动启动bash -- )
这里有很多事情要做。
首先,我们以root用户身份运行,因此默认情况下,我们获得了一整套功能。其中包括使用切换uid和gid的功能 setuidsetgid 系统调用。然而,通常当一个程序这样做时,它会

相关问题