Jas*_*ton 362 linux iptables ipv6 root linux-capabilities
在我的开发盒上有这个限制是非常烦人的,因为除了我之外不会有任何用户.
我知道标准的解决方法,但它们都没有完全符合我的要求:
是否有一些简单的sysctl
变量允许非root进程绑定到Linux上的"特权"端口(端口小于1024),或者我只是运气不好?
编辑:在某些情况下,您可以使用功能来执行此操作.
Jas*_*ton 373
好的,感谢那些指出功能系统和CAP_NET_BIND_SERVICE
功能的人.如果您有最新的内核,确实可以使用它来启动非root用户服务但绑定低端口.简短的回答是你这样做:
setcap 'cap_net_bind_service=+ep' /path/to/program
Run Code Online (Sandbox Code Playgroud)
然后随时program
执行它将具有该CAP_NET_BIND_SERVICE
功能.setcap
在debian包中libcap2-bin
.
现在注意事项:
program
具有提升权限的LD_LIBRARY_PATH,例如setcap
或suid
.因此,如果您program
使用自己的.../lib/
,您可能需要查看另一个选项,如端口转发.资源:
setcap
.注意:RHEL首先在v6中添加了这个.
Fla*_*cks 32
您可以执行端口重定向.这就是我在Linux机器上运行的Silverlight策略服务器所做的
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300
Run Code Online (Sandbox Code Playgroud)
Pau*_*lin 31
该标准的办法就是让他们"setuid的",使他们开始了为根,然后他们马上扔掉root特权,因为他们已经绑定的端口,但他们开始接受它连接之前.您可以在Apache和INN的源代码中看到这方面的好例子.我被告知Lighttpd是另一个很好的例子.
另一个例子是后缀,它使用通过管道进行通信,以及多个守护进程只有一个或它们中的两(其中做很少除了接收或发射字节)作为根,其余运行在较低的特权运行.
Jos*_*hua 23
或者修补内核并删除检查.
(最后的选择,不推荐).
在net/ipv4/af_inet.c
,删除读取的两行
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
goto out;
Run Code Online (Sandbox Code Playgroud)
并且内核将不再检查特权端口.
Gab*_*urt 19
您可以设置本地SSH隧道,例如,如果您希望端口80命中您的应用程序绑定到3000:
sudo ssh $USERNAME@localhost -L 80:localhost:3000 -N
Run Code Online (Sandbox Code Playgroud)
这具有使用脚本服务器的优点,并且非常简单.
Cyb*_*rax 18
文件功能并不理想,因为它们可能会在程序包更新后中断.
理想的解决方案,恕我直言,应该是一个创建具有可继承CAP_NET_BIND_SERVICE
集的shell的能力.
这是一个有点复杂的方法:
sg $DAEMONUSER "capsh --keep=1 --uid=`id -u $DAEMONUSER` \
--caps='cap_net_bind_service+pei' -- \
YOUR_COMMAND_GOES_HERE"
Run Code Online (Sandbox Code Playgroud)
capsh
实用程序可以在Debian/Ubuntu发行版中的libcap2-bin包中找到.这是继续发生的事情:
sg
将有效组ID更改为守护程序用户的ID.这是必要的,因为capsh
保持GID不变,我们绝对不希望它.$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"
Run Code Online (Sandbox Code Playgroud)
Ste*_*ger 17
2017年更新:
Authbind向用户/组授予信任并提供对每端口访问的控制,并支持IPv4和IPv6(最近添加了IPv6支持).
安装: apt-get install authbind
为所有用户和组配置对相关端口的访问,例如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
通过authbind
(可选指定--deep
或其他参数,请参见手册页)执行命令:
authbind --deep /path/to/binary command line args
Run Code Online (Sandbox Code Playgroud)
例如
authbind --deep java -jar SomeServer.jar
Run Code Online (Sandbox Code Playgroud)作为约书亚神话般的后续行动(=不推荐,除非你知道你做了什么)建议破解内核:
我先在这里发布.
简单.使用普通或旧内核,您不需要.
正如其他人所指出的,iptables可以转发一个端口.
正如其他人所指出的,CAP_NET_BIND_SERVICE也可以完成这项工作.
当然,如果从脚本启动程序,CAP_NET_BIND_SERVICE将失败,除非你在shell解释器上设置上限,这是没有意义的,你也可以以root身份运行你的服务...
例如对于Java,你必须应用它到JAVA JVM
sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java
Run Code Online (Sandbox Code Playgroud)
显然,这意味着任何Java程序都可以绑定系统端口.
Dito为mono/.NET.
我也很确定xinetd不是最好的想法.
但由于这两种方法都是黑客攻击,为什么不通过解除限制来解除限制呢?
没有人说你必须运行一个普通的内核,所以你可以运行自己的内核.
您只需下载最新内核的源代码(或您目前拥有的内核).然后,你去:
/usr/src/linux-<version_number>/include/net/sock.h:
Run Code Online (Sandbox Code Playgroud)
在那里你寻找这条线
/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK 1024
Run Code Online (Sandbox Code Playgroud)
并将其更改为
#define PROT_SOCK 0
Run Code Online (Sandbox Code Playgroud)
如果你不想有一个不安全的ssh情况,你可以改成它:#define PROT_SOCK 24
通常,我会使用您需要的最低设置,例如79用于http,或者在端口25上使用SMTP时为24.
这已经是全部了.
编译内核,然后安装它.
重启.
完成 - 这个愚蠢的限制是GONE,这也适用于脚本.
以下是编译内核的方法:
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 ..
Run Code Online (Sandbox Code Playgroud)
简而言之,如果你想保持安全,请使用iptables,如果你想确保这个限制再也不会困扰你,请编译内核.
Mar*_*ter 15
另外两个简单的可能性
有一个旧的(不合时宜的)解决方案是"一个守护程序,它绑定在一个低端口并将控制权交给你的守护进程".它被称为inetd(或xinetd).缺点是:
优点:
另一个替代方案:从特权端口到一些任意高编号端口的hacked-up代理(netcat甚至更强大的代理),您可以在其中运行目标守护程序.(Netcat显然不是一个生产解决方案,但"只是我的开发盒",对吧?).这样,您可以继续使用支持网络的服务器版本,只需要root/sudo启动代理(启动时),不会依赖复杂/可能脆弱的功能.
Ast*_*tro 14
我的"标准解决方法"使用socat作为用户空间重定向器:
socat tcp6-listen:80,fork tcp6:8080
Run Code Online (Sandbox Code Playgroud)
请注意,这不会扩展,分叉是昂贵的,但这是socat的工作方式.
KJ *_*dis 13
我知道这是一个老问题,但现在最近(> = 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'
Run Code Online (Sandbox Code Playgroud)
按顺序,我们是
cap_net_bind_service
功能添加到继承和环境集bash -c 'your-command'
(因为capsh
后面的参数自动启动bash --
)引擎盖下有很多内容.
首先,我们以root身份运行,因此默认情况下,我们会获得一整套功能.其中包括使用setuid
和setgid
系统调用切换uid和gid的功能.但是,通常当一个程序执行此操作时,它会丢失其功能集 - 这样就可以setuid
保留原有的root方法.该--keep=1
标志告诉capsh
发出prctl(PR_SET_KEEPCAPS)
syscall,它在更改用户时禁用功能丢弃.用户的实际变化通过capsh
与发生的--user
标志,它运行setuid
和setgid
.
我们需要解决的下一个问题是如何以我们exec
的孩子之后的方式设置能力.功能系统始终具有"继承"的一组功能,这是"在execve(2)中保留的一组功能"[ capabilities(7) ].虽然这听起来像是解决了我们的问题(只是设置了cap_net_bind_service
继承的能力,对吗?),但这实际上只适用于特权进程 - 而且我们的进程不再具有特权,因为我们已经更改了用户(带有--user
标志).
新的环境功能集解决了这个问题 - 它是"一组在非特权程序的execve(2)中保留的功能." 通过放入cap_net_bind_service
环境集,当capsh
exec是我们的服务器程序时,我们的程序将继承此功能并能够将侦听器绑定到低端口.
如果您有兴趣了解更多信息,功能手册页将详细解释这一点.运行capsh
经过strace
也非常丰富!
uru*_*sha 13
出于某种原因,没有人提到将sysctl net.ipv4.ip_unprivileged_port_start降低到所需的值.示例:我们需要将应用程序绑定到443端口.
sysctl net.ipv4.ip_unprivileged_port_start=443
Run Code Online (Sandbox Code Playgroud)
有人可能会说,存在潜在的安全问题:非特权用户现在可能绑定到其他特权端口(444-1024).但是你可以通过阻止其他端口轻松地使用iptables解决这个问题:
iptables -I INPUT -p tcp --dport 444:1024 -j DROP
iptables -I INPUT -p udp --dport 444:1024 -j DROP
Run Code Online (Sandbox Code Playgroud)
与其他方法比较.这个方法:
根据具体情况,我会在sysctl,CAP,authbind和iptables-redirect之间进行选择.我们有很多选择,这很棒.
Gre*_*pak 12
TLDR:对于"答案"(如我所见),请跳到本答案的>> TLDR <<部分.
好吧,我已经弄明白了(这次是真的),这个问题的答案,我的这个答案也是一种道歉的方式,以促进另一个答案(在这里和在推特上)我认为是"最好的"但是在尝试之后,发现我错了.从我的错误中学习孩子:在你真正尝试过之前不要宣传一些东西!
我再次回顾了这里的所有答案.我尝试了其中一些(并选择不尝试其他人,因为我根本不喜欢这些解决方案).我认为解决方案是使用systemd
它Capabilities=
和CapabilitiesBindingSet=
设置.经过一段时间的摔跤后,我发现这不是解决方案,因为:
功能旨在限制根进程!
由于OP明智地指出,这是总是最好避免(对所有的守护程序如果可能的话!).
您不能使用选项与相关的功能User=
,并Group=
在systemd
单元文件,因为能力总是当复位execev
(或任何功能)被调用.换句话说,当systemd
分叉并丢弃其权限时,功能将被重置.没有办法解决这个问题,内核中的所有绑定逻辑都是基于uid = 0的基础,而不是功能.这意味着Capabilities不太可能成为这个问题的正确答案(至少在很短的时间内).顺便提一下,setcap
正如其他人所提到的,不是解决方案.它对我不起作用,它对脚本不起作用,并且无论何时文件发生变化都会重置.
在我微薄的辩护中,我确实陈述了(在我现在删除的评论中),詹姆斯的iptables建议(OP也提到了),是"第二好的解决方案".:-P
>> TLDR <<
解决方案是systemd
与动态iptables
命令结合使用,如下所示(取自DNSChain):
[Unit]
Description=dnschain
After=network.target
Wants=namecoin.service
[Service]
ExecStart=/usr/local/bin/dnschain
Environment=DNSCHAIN_SYSD_VER=0.0.1
PermissionsStartOnly=true
ExecStartPre=/sbin/sysctl -w net.ipv4.ip_forward=1
ExecStartPre=-/sbin/iptables -D INPUT -p udp --dport 5333 -j ACCEPT
ExecStartPre=-/sbin/iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
ExecStartPre=/sbin/iptables -A INPUT -p udp --dport 5333 -j ACCEPT
ExecStartPre=/sbin/iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
ExecStopPost=/sbin/iptables -D INPUT -p udp --dport 5333 -j ACCEPT
ExecStopPost=/sbin/iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
User=dns
Group=dns
Restart=always
RestartSec=5
WorkingDirectory=/home/dns
PrivateTmp=true
NoNewPrivileges=true
ReadOnlyDirectories=/etc
# Unfortunately, capabilities are basically worthless because they're designed to restrict root daemons. Instead, we use iptables to listen on privileged ports.
# Capabilities=cap_net_bind_service+pei
# SecureBits=keep-caps
[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)
在这里我们完成以下任务:
iptables
systemd
清除我们的防火墙规则,确保在守护程序未运行时删除它们.systemd
声称),即使守护程序被泄露并设置也是如此uid=0
.iptables
不幸的是,它仍然是一个非常丑陋且难以使用的实用程序.例如,如果守护程序正在侦听,eth0:0
而不是eth0
命令略有不同.
zby*_*zek 10
systemd是一个sysvinit替代品,可以选择启动具有特定功能的守护程序.选项Capabilities =,CapabilityBoundingSet =在systemd.exec(5)联机帮助页中.
端口重定向对我们来说最有意义,但我们遇到了一个问题,我们的应用程序将在本地解析一个也需要重新路由的URL; (这意味着你shindig).
这也将允许您在访问本地计算机上的URL时重定向.
iptables -A PREROUTING -t nat -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -A OUTPUT -t nat -p tcp --dport 80 -j REDIRECT --to-port 8080
Run Code Online (Sandbox Code Playgroud)
在启动时:
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
Run Code Online (Sandbox Code Playgroud)
然后,您可以绑定到前进的端口.
使用systemd,您只需稍微修改您的服务即可接受预先激活的套接字.
您可以稍后使用systemd socket activate.
不需要功能,iptables或其他技巧.
这是来自简单python http服务器的这个示例的相关systemd文件的内容
文件 httpd-true.service
[Unit]
Description=Httpd true
[Service]
ExecStart=/usr/local/bin/httpd-true
User=subsonic
PrivateTmp=yes
Run Code Online (Sandbox Code Playgroud)
文件 httpd-true.socket
[Unit]
Description=HTTPD true
[Socket]
ListenStream=80
[Install]
WantedBy=default.target
Run Code Online (Sandbox Code Playgroud)
现代Linux支持/sbin/sysctl -w net.ipv4.ip_unprivileged_port_start=0
。