是否允许非root用户进程绑定到端口80和443?


104

是否可以调整内核参数以允许用户级程序绑定到端口80和443?

我问的原因是我认为允许特权进程打开套接字并进行监听是愚蠢的。任何打开套接字并进行侦听的操作都是高风险的,并且高风险的应用程序不应以root用户身份运行。

我宁愿尝试弄清哪个非特权进程正在侦听端口80,而不是尝试删除具有root特权的恶意软件。



10
长答案是肯定的,所以短答案也应该是。
英国电信

4
简短的答案肯定的。
杰森·C

Answers:


163

我不确定这里的其他答案和评论是指什么。这很容易做到。有两个选项,这两个选项都允许访问低编号的端口,而不必将进程提升为root:

选项1:用于CAP_NET_BIND_SERVICE向进程授予低号端口访问权限:

使用此命令,您可以通过以下setcap命令授予对特定二进制文件的永久访问权,以绑定到低号端口:

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

有关e / i / p部分的更多详细信息,请参见cap_from_text

完成此操作后,/path/to/binary将能够绑定到低编号的端口。请注意,您必须setcap在二进制文件本身而不是符号链接上使用。

选项2:authbind用于授予一次性访问权限,并具有更好的用户/组/端口控制:

authbind手册页)工具正是这个存在。

  1. authbind使用您喜欢的软件包管理器进行安装。

  2. 配置它以授予对相关端口的访问权限,例如,允许所有用户和组的80和443:

    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. 现在通过authbind(可选地指定--deep或其他参数,请参见手册页)执行命令:

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

    例如

    authbind --deep java -jar SomeServer.jar
    

上面两个都有优点和缺点。选项1将信任授予二进制文件,但不提供对每个端口访问的控制。选项2将信任授予用户/组,并提供对每个端口访问的控制,但是AFAIK仅支持IPv4。


真的需要rwx许可吗?
马特

要还原选项1中的操作,是否可以使用-pintead of 重新运行命令+eip
eugene1832 '16

5
要注意的是,使用setcap覆盖了您授予特权的可执行文件(例如,执行重建),那么它将失去其特权端口状态,您必须再次为其赋予特权:|
rogerdpack '16

1
我必须摆弄的东西;我试图运行sysv服务,该服务运行使用ruby的ruby可执行文件。您需要授予特定setcap于版本的ruby可执行文件的权限,例如/usr/bin/ruby1.9.1
Christian Rondeau

3
我怀疑chmod将777 byport文件归档是最好的主意。我看过的范围从500744。我会坚持最适合您的限制。
佩雷,

28

戴尔·哈格隆德(Dale Hagglund)就在现场。因此,我只是用一些细节和示例,以不同的方式讲同样的话。☺

在Unix和Linux世界中,正确的做法是:

  • 具有一个小型,简单,易于审核的程序,该程序可以作为超级用户运行并绑定侦听套接字;
  • 具有另一个由第一个程序产生的,小型,简单,易于审核的程序,该程序会删除特权;
  • 要在另一个单独的第三个程序中以非超级用户帐户运行该服务,并由第二个程序加载该链,希望简单地继承套接字的打开文件描述符。

您对高风险的位置有错误的认识。高风险在于从网络读取数据并采取行动,而不是通过打开套接字,将其绑定到端口并进行调用这样简单的操作来完成listen()。这是服务中进行实际通信的一部分,因此风险很高。打开,bind()和的部分,listen()甚至(在一定程度上)打开的部分accepts()都不是高风险,可以在超级用户的支持下运行。它们不会使用和处理accept()网络中不受信任的陌生人控制的数据(在这种情况下,源IP地址除外)。

有很多方法可以做到这一点。

inetd

正如Dale Hagglund所说,旧的“网络超级服务器”就是inetd这样做的。用于运行服务进程的帐户是中的列之一inetd.conf。它没有将侦听部分和放弃特权部分分成两个单独的程序,这些程序很小且易于审核,但是它确实将主服务代码分离到了一个单独的程序中,并exec()在一个带有打开文件描述符的服务过程中进行了编辑。用于插座。

审核的困难不是什么大问题,因为仅需审核一个程序即可。 inetd的主要问题不是审核太多,而是与最新的工具相比,它没有提供简单的细粒度运行时服务控制。

UCSPI-TCP和daemontools

Daniel J. Bernstein的UCSPI-TCPdaemontools软件包旨在共同实现这一目标。也可以使用Bruce Guenter的等效daemontools-encore工具集。

tcpserver从UCSPI-TCP 打开套接字文件描述符并绑定到特权本地端口的程序是。它同时执行listen()accept()

tcpserver然后生成一个服务程序,该服务程序本身会失去root特权(因为所服务的协议涉及先以超级用户身份开始,然后“登录”(例如,FTP或SSH守护程序就是这种情况)),或者setuidgid是自包含的小型且易于审核的程序,该程序仅丢弃特权,然后将加载链正确地链接到服务程序(因此,其中的任何部分都不会以超级用户特权运行,例如qmail-smtpd)。

run因此,将以一个服务脚本为例(此脚本用于提供空IDENT服务的dummyidentd):

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

sh

我的nosh软件包就是为此目的而设计的。setuidgid和其他程序一样,它的实用程序很小。略有不同是它可用于systemd-style“ LISTEN_FDS”服务以及UCSPI-TCP服务,因此传统tcpserver程序被两个单独的程序代替:tcp-socket-listentcp-socket-accept

同样,单一用途的实用程序会相互产生和加载。该设计的一个有趣的怪癖是,可以在超级用户特权之后listen()甚至之前放弃超级用户特权accept()。这里的run脚本qmail-smtpd确实可以做到这一点:

#!/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 \
'

该超级用户的支持下运行的程序是小服务无关的链装载工具fdmoveclearenvenvdirsoftlimittcp-socket-listen,和setuidgid。到sh启动时,套接字已打开并绑定到smtp端口,并且该进程不再具有超级用户特权。

s6,s6-网络和execline

Laurent Bercot的s6s6网络软件包旨在共同实现这一目标。这些命令在结构上与daemontools和UCSPI-TCP 的命令非常相似。

run除了替换s6-tcpserverfor tcpservers6-setuidgidfor 之外,脚本将几乎相同setuidgid。但是,也可能会选择同时使用M. Bercot的execline工具集。

这是一个FTP服务的示例,它是对Wayne Marshall的原始服务进行了轻微修改,它使用execline,s6,s6-networking和publicfile的FTP服务器程序:

#!/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

Gerrit Pape的ipsvd是另一个与ucspi-tcp和s6-networking相同的工具集。这些工具是chpsttcpsvd这段时间,但他们做同样的事情,而且做阅读,处理,以及由不可信的客户端通过网络发送的东西写在高风险的代码仍然是在一个单独的程序。

这是M. Papefnordrun脚本中运行的示例

#!/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,可以在某些Linux发行版中找到的新服务监督和初始化系统,旨在做inetd可以做的事情。但是,它不使用一组小型独立程序。systemd不幸的是,必须对整个系统进行审计。

systemd一个创建配置文件以定义一个systemd侦听的套接字和一个systemd启动的服务。服务“单元”文件的设置允许对服务过程进行大量控制,包括以哪个用户身份运行。

在将该用户设置为非超级用户的情况下,systemd完成打开套接字,将其绑定到端口并在进程#1中以超级用户身份调用listen()(以及在需要时调用accept())的所有工作,以及该服务的处理过程生成运行时没有超级用户权限。


2
谢谢你的赞美。这是大量的具体建议。+1。
Dale Hagglund 2014年

11

我有一个完全不同的方法。我想将80端口用于node.js服务器。因为为非sudo用户安装了Node.js,所以我无法执行此操作。我尝试使用符号链接,但对我而言不起作用。

然后我知道我可以将连接从一个端口转发到另一个端口。因此,我在端口3000上启动了服务器,并设置了一个从端口80转发至端口3000的端口。

该链接提供了可用于执行此操作的实际命令。这是命令-

本地主机/环回

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

外部

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

我使用了第二个命令,它对我有用。因此,我认为这是不允许用户进程直接访问较低端口,而是使用端口转发对其进行访问的中间立场。


6
开箱即用的思维方式+1
理查德·怀斯曼

4

您的直觉是完全正确的:以root用户身份运行大型复杂程序是一个坏主意,因为它们的复杂性使它们难以信任。

但是,允许普通用户绑定到特权端口也是一个坏主意,因为此类端口通常代表重要的系统服务。

解决此明显矛盾的标准方法是特权分离。基本思想是将程序分为两个(或多个)部分,每个部分在整个应用程序中定义明确,并通过简单的有限接口进行通信。

在您给出的示例中,您希望将程序分为两部分。一个以root用户身份运行并打开并绑定到特权套接字,然后以某种方式将其交给另一部分,该部分以普通用户身份运行。

这两种主要方法可以实现这种分离。

  1. 以root身份启动的单个程序。它所做的第一件事就是以尽可能简单和有限的方式创建必要的套接字。然后,它放弃特权,也就是说,它将自身转换为常规用户模式进程,并执行所有其他工作。正确放弃特权是很棘手的,因此请花点时间研究正确的方法。

  2. 通过父进程创建的套接字对进行通信的一对程序。非特权驱动程序接收初始参数,并可能执行一些基本参数验证。它通过socketpair()创建一对连接的套接字,然后派生并执行另外两个程序,它们将完成实际工作,并通过套接字对进行通信。其中之一具有特权,将创建服务器套接字以及任何其他特权操作,而另一种将执行更复杂的应用程序,因此可信度较低。

[1] http://en.m.wikipedia.org/wiki/Privilege_separation


您的建议不被视为最佳实践。您可能会看到inetd,它可以在特权套接字上侦听,然后将该套接字移交给非特权程序。
戴尔·哈格隆德2014年

3

最简单的解决方案:删除Linux上的所有特权端口

适用于ubuntu / debian:

#save configuration permanently
echo 'net.ipv4.ip_unprivileged_port_start=0' > /etc/sysctl.d/50-unprivileged-ports.conf
#apply conf
sysctl --system

(适用于具有非root帐户的VirtualBox)

现在,请注意安全性,因为所有用户都可以绑定所有端口!


那很聪明。一个小巧的选择:该配置会打开80和443,但同时还会打开所有其他端口。可能不需要其他端口上的放宽权限。
jww
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.