分享几个让 Linux 非 Root 用户运行的程序使用特权端口的技巧

Posted by Mike on 2020-05-13

众所周知,在 Linux 系统下,只允许 Root 用户运行的程序才可以使用特权端口 ( 1024 以下的端口 )。如果在普通用户下使用特权端口将会报错。

在一些特定的环境下,我们可能考虑到程序运行在 Root 帐户下,可能会给 Linux 系统带来安全风险。希望能让普通用户启动的程序运行在特权端口上,比如:Web 服务器。

那如何能够让普通用户启动的程序运行在特权端口呢?本文将介绍一些方法,让你能够解决这个问题。

通过设置 CAP_NET_BIND_SERVICE 实现

Linux 内核从 2.6.24 版本开始就有了能力的概念,这使得普通用户也能够做只有超级用户才能完成的工作。

使用 setcap 命令让指定程序拥有绑定端口的能力,这样即使程序运行在普通用户下,也能够绑定到 1024 以下的特权端口上。

1
2
# 给指定程序设置 CAP_NET_BIND_SERVICE 能力
$ setcap cap_net_bind_service=+eip /path/to/application

下面我们来看一个实例,以 Nginx 为例:

如果你的程序不再需要使用这个能力,你可以使用以下命令来清除。

1
$ setcap -r /path/to/application
  1. 这个方法并不是所有 Linux 系统通用,Linux 内核在 2.6.24 之前的并没有提供此项能力,因此你需要检查要使用此方法所在系统是否支持。

  2. 另外需要注意的是,如果要运行的程序是一个脚本,这个方法是没有办法正常工作的。

通过端口转发实现

如果要运行的程序有权限监听其他端口,那么这个方法是可以使用的。首先让程序运行在普通用户下,并绑定高于 1024 的端口。在确保能正常工作的时候,我们将通过端口转发将低端口的请求转到应用所在的高端口,从而实现普通用户启动的程序绑定到低端口。要使用此方法可以使用下面的方式。

  1. 配置内核参数以启用转发功能
1
2
# Enable the IP FORWARD kernel parameter.
$ sysctl -w net.ipv4.ip_forward=1

以上方法是临时性设置,重启之后将会被重置。如果你想长期保存,需要在 /etc/sysctl.conf 文件内修改:

1
2
3
4
5
$ vim  /etc/sysctl.conf

# Default value is 0, need change to 1.
# net.ipv4.ip_forward = 0
net.ipv4.ip_forward = 1

然后,使用 sysctl 命令从文件中加载新的配置,并使其生效。

1
2
3
4
5
# load new sysctl.conf
$ sysctl -p /etc/sysctl.conf

# or sysctl -p
# default filename is /etc/sysctl.conf
  1. 配置转发规则

这里我们使用 Iptables 来配置的转发规则,以实现端口转发到程序所在的端口。

1
2
3
# 将 80 端口转发到 8088
$ iptables -F -t nat
$ iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to:8088

此种方法能够比较好的达到我们的目的,我们的程序可以通过普通用户来运行,并能够对外提供低端口号的服务。

通过 authbind 实现

authbind 是一个支持普通用户就能绑定系统特权端口的程序,你只需要使用 authbind 程序来调用需要使用特权端口的程序就可以了。

  1. 安装 authbind
  • Debian / Ubuntu
1
$ sudo apt-get install authbind
  • CentOS / RHEL

CentOS 系列的系统安装起来相对就要麻烦一些,因为官方仓库并没有提供编译好的软件包。不过幸运的是,已经有人编译好了对应的软件包,我们只需要直接安装就可以了。

1
$ sudo rpm -ivh https://s3.amazonaws.com/aaronsilber/public/authbind-2.1.1-0.1.x86_64.rpm
  1. 配置 authbind

authbind 默认的配置文件在 /etc/authbind 目录下,里面有三个目录:byportbyaddrbyuid

假如我们有一个 test 的普通账号,想运行一个程序并绑定在 80 端口上。我们需要配置以下内容:

1
2
3
4
5
# 在 byport 目录下建立 80 文件
$ sudo touch /etc/authbind/byport/80
# 设置 test 账户有 80 文件的使用权限
$ sudo chmod 755 /etc/authbind/byport/80
$ sudo chown test.test /etc/authbind/byport/80
  1. 使用 authbind 运行指定程序

在你要启动的命令前加上 authbind --deep 命令即可。例如:要用 test 这个普通用户启动 Nginx 并绑定在 80 端口,只需执行以下命令即可:

1
$ authbind --deep "/usr/bin/nginx" -c "/etc/nginx/nginx.conf"

我们也可以直接在 IP 地址上直接绑定端口,只需在 byaddr 目录下建立 ip:port 文件就可以了。

通过 SetUID 实现

SetUID 这一特性可以让只有普通用户权限的应用程序用 Root 权限来运行,我们可以看到系统下 /usr/bin/passwd 这个文件,就使用了 SetUID。这样就使得系统的每个普通用户都能用 passwd 来修改密码,因为修改密码需要更改 /etc/passwd 文件,而默认这个文件只有 Root 用户才有权限访问。

1
2
3
4
5
# 将程序的所有者更改为 root
$ chown root.root /path/to/application

# 给程序设置 SetUID
$ chmod u+s /path/to/application

既然要使用普通用户运行程序,目的就是要降低程序本身给系统带来的安全风险。因此,本方法使用的时候需要特别谨慎,特别是当要执行的程序本身存在安全风险。

参考文档

  1. https://www.cnblogs.com/chenjunjie12321/p/9226279.html
  2. https://blog.csdn.net/Becivells/article/details/52842019
  3. https://my.oschina.net/guol/blog/186430
  4. https://github.com/tootedom/authbind-centos-rpm
  5. https://dzone.com/articles/running-tomcat-port-80-user
  6. http://blog.useasp.net/archive/2015/07/09/non-root-user-application-bind-to-ports-less-than-1024-without-root-access.aspx
  7. https://stackoverflow.com/questions/413807/is-there-a-way-for-non-root-processes-to-bind-to-privileged-ports-on-linux
  8. https://aaronsilber.me/2016/04/24/install-authbind-on-centos-7-x86_64-download-the-rpm/
  9. https://blog.webhosting.net/how-to-get-tomcat-running-on-centos-7-2-using-privileged-ports-1024/