前段时间在面试的时候,本来面的一切顺利,但是在聊到nginx的时候,面试官突然提问到:“你平时nginx都是用什么用户启动的?”,我一愣,猜想肯定有坑,但也只能见招拆招了,“nginx用户”,果不其然,面试官立马接下一招:"那你用nginx用户启动nginx,这时候nginx还能监听80端口嘛?"我一愣,就这?按照平时使用nginx的经验,我回答到:“能”。但是面试官一叹气:“再回去多看看吧”。我脑海中模糊的闪过一些系统端口和系统用户的知识,但为时已晚,一结束面试,马上开始查漏补缺。
一下面试,我赶紧打开了虚拟机,一查nginx配置文件:user nginx
,没错,配置的是nginx用户,ps -ef|grep nginx
一下,认真查看之下,我发现了为什么我会觉得nginx用户能监听80端口了。
[root@192 ~]# ps -ef|grep nginx
root 58200 1 0 11月03 ? 00:00:00 nginx: master process /usr/sbin/nginx
nginx 58201 58200 0 11月03 ? 00:00:01 nginx: worker process
nginx 58202 58200 0 11月03 ? 00:00:00 nginx: worker process
nginx的worker进程是用来处理实际的网络请求的,但是配置文件是由master进程读取再来创建worker进程,也就是说我们在配置文件中配置的user nginx
,实际上是为worker进程设置的。master进程所属者为执行nginx命令的用户,实际上的端口绑定也是由master进程负责的,但是平时在nginx配置文件设置完后一般喜欢直接用root用户启动nginx,所以平时的把nginx的用户设置为nginx,nginx也能监听80端口的错误印象就是从这里来的。
[nginx@192 sbin]$ ./nginx
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
事实也确实是这样,用普通用户去执行nginx,就会报权限被拒绝的错误。
了解了现象之后,就得去了解原理了,为什么在Linux中,nginx用户不能去使用80端口呢?那这就得去了解一下系统用户和系统端口的知识了
Linux中系统分为三种:
1-499的uid是系统自留的,所以当我们创建用户时,如果不使用-u
参数指定uid,那么uid是一定大于等于500的
端口的范围:端口号的范围是从0到65535。这些端口号,根据用途可分为三个类别(范围):
系统端口可不是给系统用户用的,事实上系统端口只有超级用户能使用,其他用户边都别来挨。
[root@192 App]# useradd test -u100
[root@192 App]# id test
uid=100(test) gid=1002(test) 组=1002(test)
[root@192 App]# su test
[test@192 App]$ cd nginx-1.24.0/
[test@192 nginx-1.24.0]$ sbin/nginx
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
经过测试得知,系统端口只能由超级管理员使用,其他用户就别想用了。
一个用户占用这么多端口,其他用户肯定嫉妒的眼红,那有没有什么办法让普通用户也能用上系统端口呢?肯定是有的,而且不只一种。
[root@192 App]# useradd t -u0 -o # 把用户id指定位0
[root@192 App]# id t
uid=0(root) gid=0(root) 组=0(root)
[root@192 App]# nginx-1.24.0/sbin/nginx # 忽悠成功
事实上,我们在创建用户的时候,可以用-u
参数指定uid,然后使用-o
参数指定用户可以使用已被使用的uid,这样就能成功骗过系统,让系统认为这个用户也是超级管理员(虽然就是)。因为Linux系统中判断用户是根据用户uid来判断的,所以Linux中名字不重要,uid才重要。
在Linux中,除了rwx权限之外,还有一种特殊权限s,这种权限只对二进制可执行文件有效,如/usr/bin/passwd就加上了suid权限,当一个普通用户在执行这个命令的时候,其实是root用户在执行命令
[root@localhost sbin]# file /usr/bin/passwd
/usr/bin/passwd: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=87e17c1d9b2e20d7e8aeab9115074375eec5e8e1, stripped
[root@localhost sbin]# ll /usr/bin/passwd
-rwsr-xr-x. 1 root root 33600 4月 7 2020 /usr/bin/passwd
只有在这里有ELF
的才是二进制文件,suid权限对其他文件没有效果
setcap
命令是Linux命令,用来设置文件的能力(capabilities)。在Linux系统中,能力是一种比权限模型更细粒度的权限控制机制。通过将root用户的特权分割成不同的能力,每种能力代表一定的特权操作。如:CAP_SYS_MODULE表示能加载内核模块的特权,CAP_SETUID表示用户能够修改用户身份。
setcap [-q] [-n <rootuid>] [-v] { capabilities|-|-r} filename
# capabilities:设置的能力
# 可以使用man setcap来查看更多信息
[root@localhost sbin]# setcap 'CAP_NET_BIND_SERVICE=+ep' nginx
[root@localhost sbin]# getcap nginx
nginx = cap_net_bind_service+ep
# 使用getcap查看能力
在Linux中,任何用户都能提权为root,可以使用visudo
进行设置,也可以直接对/etc/sudoers
文件进行修改
# root表示用户名
# 第一个ALL表示适用的主机
# 第二个ALL为提权为什么用户
# 第三个ALL为可以执行什么命令
root ALL=(ALL) NOPASSWD: ALL
## Allows people in group wheel to run all commands
%wheel ALL=(ALL) ALL