linux普通用户监听1024以下的端口(80、443)

本文介绍了非root用户在Linux系统中如何监听1024以下的端口,包括通过nginx反向代理、iptables端口转发、setuid、CAP_NET_BIND_SERVICE权限设置等方法,并详细讲解了每种方法的优缺点和操作步骤。

最近为了安全,不打算让Nginx以root权限启动,网上查了查资料,这里整理一下分享给大家

1、介绍

linux对于非root权限用户不能使用1024以下的端口,对于一些服务,过高的权限,会带来一定的风险。那么对于低权限的用户如何对外开放1024以下的端口。我这里找到几种办法并且亲测可行

首先搭建环境 centos7 账户 tengine 没有 sudo 权限。

2、nginx进程属主

关于nginx进程属主的问题总结如下:

2.1 规则

nginx启动进程可以在conf里指定user(user  work;)但是这个只有在用root启动的情况有意义,

如果是用其他用户启动的nginx master是没有意义的 nginx会忽略这个配置,如下nginx warning所述

nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /home/work/app/nginx/conf/nginx.conf:1

2.2 结论

1,在非root账户下启动时,nignx的master和worker进程的owner都将是这个账户,

2,在root账户下启动时 nignx的master进程是的owner是root,worker的owner在conf已配置用户的情况下,owner是配置的用户,否则将是nobody,而且也可能导致nginx的一些文件的owner也是nobody

3、方式

3.1 nginx 等软件做反向代理

利用 nginx 做反向代理,nginx 监听 80 端口,将请求转发到实际监听的8080端口,示例:

server {
    listen 80;
    location / {
        proxy_pass http://192.168.1.110:8080
    }
}

3.2 iptables端口转发

首先程序绑定1024以上的端口,然后root权限下做转发注意有些系统需要手动开启IP FORWARD功能

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

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

# Enable the IP FORWARD kernel parameter. 
sysctl -w net.ipv4.ip_forward=1   

# Use iptables rules to redirect packets 
iptables -F -t nat iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to:8088

第一步使用sysctl确保启用IP FORWARD功能(此功能在Red Hat/CentOS默认是被禁用的),注意,代码中使用的sysctl设置是临时性设置,重启之后将会被重置,如果要长久保存,需要在/etc/sysctl.conf文件内修改:

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

然后从文件中加载新的配置

# load new sysctl.conf 
sysctl -p /etc/sysctl.conf   

# or sysctl -p # default filename is /etc/sysctl.conf

第二步就是使用iptables的规则来实现端口转发到程序所在的端口,示例中我们要将80端口转发到8088。

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

3.3 setuid

为用户的应用程序在执行位设置user ID能够使程序可以有root权限来运行,这个方法让程序能够像在root下运行有同样的效果,不过需要非常小心,这种方法同样会带来安全风险,特别是当要执行的程序本身存在安全风险

使用的方法是:

chown root:root /path/to/application #使用SetUID 
chmod u+s /path/to/application

我们可以看到在系统下,/usr/bin/passwd这种文件,就使用了SetUID,使得每个系统的用户都能用passwd来修改密码——这是要修改/etc/passwd的文件(而这个只有root有权限)。

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

root账户下执行

chown root:root nginx
chmod 4755 nginx

从图片可以看出来nginx可以运行,但是主进程仍然是以root权限运行,这样并不安全。

3.4 CAP_NET_BIND_SERVICE

在 Linux 内核版本 2.2 开始,Linux 将一系列的超级管理员权限细分成了一个个可以单独开启关闭的单元,以提供更细粒度的权限控制,这些单元,就被称之为 capabilities。详细的 capabilities 列表可以参考 capabilities(7): overview of capabilities - Linux man page

Linux内核中Capabilities的实现机制
     Linux内核从2.2版本开始,就加进的Capabilities的概念与机制,并随着版本升高逐步得到改进。在linux中,root权限被分割成一下29中能力:

CAP_CHOWN:修改文件属主的权限
CAP_DAC_OVERRIDE:忽略文件的DAC访问限制
CAP_DAC_READ_SEARCH:忽略文件读及目录搜索的DAC访问限制
CAP_FOWNER:忽略文件属主ID必须和进程用户ID相匹配的限制
CAP_FSETID:允许设置文件的setuid位
CAP_KILL:允许对不属于自己的进程发送信号
CAP_SETGID:允许改变进程的组ID
CAP_SETUID:允许改变进程的用户ID
CAP_SETPCAP:允许向其他进程转移能力以及删除其他进程的能力
CAP_LINUX_IMMUTABLE:允许修改文件的IMMUTABLE和APPEND属性标志
CAP_NET_BIND_SERVICE:允许绑定到小于1024的端口
CAP_NET_BROADCAST:允许网络广播和多播访问
CAP_NET_ADMIN:允许执行网络管理任务
CAP_NET_RAW:允许使用原始套接字
CAP_IPC_LOCK:允许锁定共享内存片段
CAP_IPC_OWNER:忽略IPC所有权检查
CAP_SYS_MODULE:允许插入和删除内核模块
CAP_SYS_RAWIO:允许直接访问/devport,/dev/mem,/dev/kmem及原始块设备
CAP_SYS_CHROOT:允许使用chroot()系统调用
CAP_SYS_PTRACE:允许跟踪任何进程
CAP_SYS_PACCT:允许执行进程的BSD式审计
CAP_SYS_ADMIN:允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等
CAP_SYS_BOOT:允许重新启动系统
CAP_SYS_NICE:允许提升优先级及设置其他进程的优先级
CAP_SYS_RESOURCE:忽略资源限制
CAP_SYS_TIME:允许改变系统时钟
CAP_SYS_TTY_CONFIG:允许配置TTY设备
CAP_MKNOD:允许使用mknod()系统调用
CAP_LEASE:允许修改文件锁的FL_LEASE标志

CAP_NET_BIND_SERVICE

拥有这个 capability 的程序,就可以绑定端口号在 1024 以下的特权端口。

setcap

那么,该如何控制每个 capability 呢?答案就是 setcap 命令。上文所提到的命令,就是给指定的这个二进制程序增加 CAP_NET_BIND_SERVICE 这个 capability

在 capability 名后面,用加号相连接的,则是开启这个 capability 的模式。模式有如下三种:

  • e: Effective,意为这个 capability 是启用的。
  • p: Permitted,意为这个 capability 是允许被使用的。
  • i: inherited,意为这个 capability 可以被其子进程继承。

在 setcap 命令中,使用加号来开启这个模式,或者使用减号来关闭这个模式。

有什么副作用

这个方法确实有一些副作用,或者说是限制:

  1. 这个方法对脚本无效。如果要使某个脚本拥有这个能力,则需要为其解释器赋予这个能力,而这明显是一个巨大的安全隐患。
  2. Linux 会为使用了 setcap 或 suid 的程序禁用掉 LD_LIBRARY_PATH

3.4.1 Nginx应用

使用的方法:

sudo setcap cap_net_bind_service=+eip /home/tengine/nginx/tengine/sbin/nginx

切换到 tengine 账户下,信息如下:

[root@centos7 sbin]# setcap cap_net_bind_service=+eip /home/tengine/nginx/tengine/sbin/nginx
[root@centos7 sbin]# su tengine
[tengine@centos7 sbin]$ stat nginx
  文件:"nginx"
  大小:6054330         块:11832      IO 块:4096   普通文件
设备:fd00h/64768d      Inode:397136      硬链接:1
权限:(0755/-rwxr-xr-x)  Uid:( 1001/ tengine)   Gid:( 1001/ tengine)
最近访问:2016-10-11 18:43:05.402239835 +0800
最近更改:2016-10-11 18:25:47.273183401 +0800
最近改动:2016-10-11 18:48:23.084257104 +0800
创建时间:-
[tengine@centos7 sbin]$ ./nginx
[tengine@centos7 sbin]$ ps -aux| grep nginx
tengine  18014  0.0  0.1  45500  1124 ?        Ss   18:49   0:00 nginx: master process ./nginx
tengine  18015  0.0  0.1  45960  1596 ?        S    18:49   0:00 nginx: worker process
tengine  18017  0.0  0.0 112664   984 pts/0    R+   18:49   0:00 grep --color=auto nginx
[tengine@centoshttps://superuser.com/questions/710253/allow-non-root-process-to-bind-to-port-80-and-4437 sbin]$

最后别忘记怎么清除这个能力

 setcap -r nginx

3.4.2 java应用

使用root用户:

setcap CAP_NET_BIND_SERVICE=+eip /usr/local/java1.8/bin/java  #假设JAVA_HOME为/usr/local/java1.8

java -version 
#会出现错误java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directory

ln -s /usr/local/java1.8/lib/amd64/jli/libjli.so /usr/lib/
ldconfig
java -version  

使用普通用户

# 使用普通用户需要是sudoer
sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/local/java1.8/bin/java  #假设JAVA_HOME为/usr/local/java1.8

sudo ln -s /usr/local/java1.8/lib/amd64/jli/libjli.so /usr/lib/

sudo ldconfig


3.5 设置port_start

linux 允许非 root 用户默认只能使用 1024 以上端口,sysctl 可以修改该起始端口。

例:允许非root用户使用所有端口

#临时生效
sysctl net.ipv4.ip_unprivileged_port_start=0
#永久生效
echo "net.ipv4.ip_unprivileged_port_start=0" >> /etc/sysctl.conf

其他linux内核参数见 https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
 

4. 参考:

linux普通用户使用1024以下的端口(80) - 简书

nginx进程属主问题讨论 - luxianghao - 博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值