有没有办法让非 root 进程绑定到 Linux 上的“特权”端口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/413807/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a way for non-root processes to bind to "privileged" ports on Linux?
提问by Jason Creighton
It's very annoying to have this limitation on my development box, when there won't ever be any users other than me.
在我的开发箱上有这个限制是非常烦人的,因为除了我之外永远不会有任何用户。
I'm aware of the standard workarounds, but none of them do exactly what I want:
我知道标准的解决方法,但没有一个完全符合我的要求:
- authbind(The version in Debian testing, 1.0, only supports IPv4)
- Using the iptables REDIRECT target to redirect a low port to a high port(the "nat" table is not yet implemented for ip6tables, the IPv6 version of iptables)
- sudo (Running as root is what I'm trying to avoid)
- SELinux (or similar). (This is just my dev box, I don't want to introduce a lot of extra complexity.)
- authbind(Debian 测试中的版本,1.0,仅支持 IPv4)
- 使用 iptables REDIRECT 目标将低端口重定向到高端口(ip6tables 的“nat”表尚未实现,iptables 的 IPv6 版本)
- sudo (以 root 身份运行是我试图避免的)
- SELinux(或类似的)。(这只是我的开发箱,我不想引入很多额外的复杂性。)
Is there some simple sysctl
variable to allow non-root processes to bind to "privileged" ports (ports less than 1024) on Linux, or am I just out of luck?
是否有一些简单的sysctl
变量允许非 root 进程绑定到 Linux 上的“特权”端口(端口小于 1024),或者我只是运气不好?
EDIT: In some cases, you can use capabilitiesto do this.
编辑:在某些情况下,您可以使用功能来执行此操作。
采纳答案by Jason Creighton
Okay, thanks to the people who pointed out the capabilities system and CAP_NET_BIND_SERVICE
capability. If you have a recent kernel, it is indeed possible to use this to start a service as non-root but bind low ports. The short answer is that you do:
好的,感谢指出能力系统和CAP_NET_BIND_SERVICE
能力的人。如果您有最新的内核,确实可以使用它以非 root 身份启动服务但绑定低端口。简短的回答是你这样做:
setcap 'cap_net_bind_service=+ep' /path/to/program
And then anytime program
is executed thereafter it will have the CAP_NET_BIND_SERVICE
capability. setcap
is in the debian package libcap2-bin
.
然后随时program
执行此后它将具有此CAP_NET_BIND_SERVICE
功能。setcap
在 debian 包中libcap2-bin
。
Now for the caveats:
现在的警告:
- You will need at least a 2.6.24 kernel
- This won't work if your file is a script. (ie, uses a #! line to launch an interpreter). In this case, as far I as understand, you'd have to apply the capability to the interpreter executable itself, which of course is a security nightmare, since any program using that interpreter will have the capability. I wasn't able to find any clean, easy way to work around this problem.
- Linux will disable LD_LIBRARY_PATH on any
program
that has elevated privileges likesetcap
orsuid
. So if yourprogram
uses its own.../lib/
, you might have to look into another option like port forwarding.
- 你至少需要一个 2.6.24 内核
- 如果您的文件是脚本,这将不起作用。(即,使用 #! 行启动解释器)。在这种情况下,据我所知,您必须将该功能应用于解释器可执行文件本身,这当然是一个安全噩梦,因为任何使用该解释器的程序都将具有该功能。我找不到任何干净、简单的方法来解决这个问题。
- Linux 将禁用任何
program
具有提升权限的LD_LIBRARY_PATH,例如setcap
或suid
。因此,如果您program
使用它自己的.../lib/
,您可能需要研究另一个选项,如端口转发。
Resources:
资源:
- capabilities(7) man page. Read this long and hard if you're going to use capabilities in a production environment. There are some really tricky details of how capabilities are inherited across exec() calls that are detailed here.
- setcap man page
- "Bind ports below 1024 without root on GNU/Linux": The document that first pointed me towards
setcap
.
- 能力(7) 手册页。如果您要在生产环境中使用功能,请仔细阅读本文。关于如何跨 exec() 调用继承功能的一些非常棘手的细节,在此处详述。
- setcap 手册页
- “在 GNU/Linux 上无需 root 即可绑定 1024 以下的端口”:首先将我指向
setcap
.
Note: RHEL first added this in v6.
回答by Paul Tomblin
The standard way is to make them "setuid" so that they start up as root, and then they throw away that root privilege as soon as they've bound to the port but before they start accepting connections to it. You can see good examples of that in the source code for Apache and INN. I'm told that Lighttpd is another good example.
标准方法是将它们设置为“setuid”,以便它们以 root 身份启动,然后一旦绑定到端口,但在开始接受与端口的连接之前,它们就丢弃该 root 特权。你可以在 Apache 和 INN 的源代码中看到很好的例子。我听说 Lighttpd 是另一个很好的例子。
Another example is Postfix, which uses multiple daemons that communicate through pipes, and only one or two of them (which do very little except accept or emit bytes) run as root and the rest run at a lower privilege.
另一个例子是 Postfix,它使用多个通过管道进行通信的守护进程,其中只有一个或两个(除了接受或发出字节之外做的很少)以 root 身份运行,其余的以较低的权限运行。
回答by Joshua
Or patch your kernel and remove the check.
或者修补您的内核并删除检查。
(Option of last resort, not recommended).
(最后的选择,不推荐)。
In net/ipv4/af_inet.c
, remove the two lines that read
在 中net/ipv4/af_inet.c
,删除读取的两行
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
goto out;
and the kernel won't check privileged ports anymore.
并且内核将不再检查特权端口。
回答by Joachim Sauer
Linux supports capabilitiesto support more fine-grained permissions than just "this application is run as root". One of those capabilities is CAP_NET_BIND_SERVICE
which is about binding to a privileged port (<1024).
Linux支持功能,支持不只是“此应用程序以root身份运行”更细粒度的权限。其中一项功能是CAP_NET_BIND_SERVICE
绑定到特权端口 (<1024)。
Unfortunately I don't know how to exploit that to run an application as non-root while still giving it CAP_NET_BIND_SERVICE
(probably using setcap
, but there's bound to be an existing solution for this).
不幸的是,我不知道如何利用它以非 root 用户身份运行应用程序,同时仍然提供它CAP_NET_BIND_SERVICE
(可能使用setcap
,但肯定会有一个现有的解决方案)。
回答by Martin Carpenter
Two other simple possibilities:
另外两个简单的可能性:
There is an old (unfashionable) solution to the "a daemon that binds on a low port and hands control to your daemon". It's called inetd (or xinetd). The cons are:
对于“绑定在低端口上并将控制权交给您的守护程序的守护程序”有一个旧的(不合时宜的)解决方案。它被称为inetd(或xinetd)。缺点是:
- your daemon needs to talk on stdin/stdout (if you don't control the daemon -- if you don't have the source -- then this is perhaps a showstopper, although some services may have an inetd-compatibility flag)
- a new daemon process is forked for every connection
- it's one extra link in the chain
- 您的守护进程需要在 stdin/stdout 上进行通信(如果您不控制守护进程——如果您没有源——那么这可能是一个阻碍,尽管某些服务可能具有 inetd-compatibility 标志)
- 为每个连接分叉一个新的守护进程
- 这是链条中的一个额外环节
Pros:
优点:
- available on any old UNIX
- once your sysadmin has set up the config, you're good to go about your development (when you re-build your daemon, might you lose setcap capabilities? And then you'll have to go back to your admin "please sir...")
- daemon doesn't have to worry about that networking stuff, just has to talk on stdin/stdout
- can configure to execute your daemon as a non-root user, as requested
- 在任何旧的 UNIX 上可用
- 一旦你的系统管理员设置了配置,你就可以开始你的开发(当你重新构建你的守护进程时,你会失去 setcap 功能吗?然后你必须回到你的管理员那里“请先生.. .”)
- 守护进程不必担心网络问题,只需要讨论标准输入/标准输出
- 可以根据要求配置为以非 root 用户身份执行您的守护程序
Another alternative: a hacked-up proxy (netcat or even something more robust) from the privileged port to some arbitrary high-numbered port where you can run your target daemon. (Netcat is obviously not a production solution, but "just my dev box", right?). This way you could continue to use a network-capable version of your server, would only need root/sudo to start proxy (at boot), wouldn't be relying on complex/potentially fragile capabilities.
另一种选择:从特权端口到某个任意高编号端口的黑客代理(netcat 或什至更强大的东西),您可以在其中运行目标守护程序。(Netcat 显然不是生产解决方案,而是“只是我的开发箱”,对吗?)。这样您就可以继续使用具有网络功能的服务器版本,只需要 root/sudo 来启动代理(在启动时),不会依赖复杂/潜在的脆弱功能。
回答by Astro
My "standard workaround" uses socat as the user-space redirector:
我的“标准解决方法”使用 socat 作为用户空间重定向器:
socat tcp6-listen:80,fork tcp6:8080
Beware that this won't scale, forking is expensive but it's the way socat works.
请注意,这不会扩展,分叉很昂贵,但这是 socat 的工作方式。
回答by FlappySocks
You can do a port redirect. This is what I do for a Silverlight policy server running on a Linux box
您可以进行端口重定向。这就是我为在 Linux 机器上运行的 Silverlight 策略服务器所做的
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300
回答by Cyberax
File capabilities are not ideal, because they can break after a package update.
文件功能并不理想,因为它们可能会在软件包更新后中断。
The ideal solution, IMHO, should be an ability to create a shell with inheritable CAP_NET_BIND_SERVICE
set.
恕我直言,理想的解决方案应该是能够创建具有可继承CAP_NET_BIND_SERVICE
集的外壳。
Here's a somewhat convoluted way to do this:
这是一个有点复杂的方法来做到这一点:
sg $DAEMONUSER "capsh --keep=1 --uid=`id -u $DAEMONUSER` \
--caps='cap_net_bind_service+pei' -- \
YOUR_COMMAND_GOES_HERE"
capsh
utility can be found in libcap2-bin package in Debian/Ubuntu distributions. Here's what goes on:
capsh
实用程序可以在 Debian/Ubuntu 发行版的 libcap2-bin 包中找到。这是发生了什么:
sg
changes effective group ID to that of the daemon user. This is necessary becausecapsh
leaves GID unchanged and we definitely do not want it.- Sets bit 'keep capabilities on UID change'.
- Changes UID to
$DAEMONUSER
- Drops all caps (at this moment all caps are still present because of
--keep=1
), except inheritablecap_net_bind_service
- Executes your command ('--' is a separator)
sg
将有效组 ID 更改为守护程序用户的组 ID。这是必要的,因为capsh
保持 GID 不变,我们绝对不想要它。- 设置位“保持 UID 更改的能力”。
- 将 UID 更改为
$DAEMONUSER
- 删除所有大写(此时所有大写仍然存在,因为
--keep=1
),除了可继承cap_net_bind_service
- 执行你的命令('--' 是一个分隔符)
The result is a process with specified user and group, and cap_net_bind_service
privileges.
结果是具有指定用户和组以及cap_net_bind_service
特权的进程。
As an example, a line from ejabberd
startup script:
例如,ejabberd
启动脚本中的一行:
sg $EJABBERDUSER "capsh --keep=1 --uid=`id -u $EJABBERDUSER` --caps='cap_net_bind_service+pei' -- $EJABBERD --noshell -detached"
回答by zbyszek
systemdis a sysvinit replacement which has an option to launch a daemon with specific capabilities. Options Capabilities=, CapabilityBoundingSet= in systemd.exec(5)manpage.
systemd是 sysvinit 的替代品,它可以选择启动具有特定功能的守护进程。选项 Capabilities=, CapabilityBoundingSet= 在systemd.exec(5)联机帮助页中。
回答by James
At startup:
启动时:
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
Then you can bind to the port you forward to.
然后你可以绑定到你转发的端口。