关于apache的运行用户

系统安装、升级讨论
版面规则
我们都知道新人的确很菜,也喜欢抱怨,并且带有浓厚的Windows习惯,但既然在这里询问,我们就应该有责任帮助他们解决问题,而不是直接泼冷水、简单的否定或发表对解决问题没有任何帮助的帖子。乐于分享,以人为本,这正是Ubuntu的精神所在。
回复
wgj
帖子: 294
注册时间: 2007-06-02 20:00

关于apache的运行用户

#1

帖子 wgj » 2015-02-09 20:46

一般来说为了安全着想,运行apache的用户不是root,而已类似于www-data之类的低权限nologin用户。但是只有root才能监听80端口。
很久以前自己编译的时候是让apache监听8080,然后用iptables把80的包转到8080间接实现。
今天研究了以下ubunt下的apache监听80端口的方式,搞不懂。
root@wgjak47-M410:/home/wgjak47# lsof -i:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
apache2 2018 root 3u IPv6 16511 0t0 TCP *:http (LISTEN)
apache2 10489 www-data 3u IPv6 16511 0t0 TCP *:http (LISTEN)
apache2 10490 www-data 3u IPv6 16511 0t0 TCP *:http (LISTEN)
为啥会有三个进程?既有root用户的也有www-data的。

无责任YY:会不会是通过root用户运行的进程监听80端口,然后通过socket转发给www-data的?

求大神指教。 :em01
poloshiao
论坛版主
帖子: 18279
注册时间: 2009-08-04 16:33

Re: 关于apache的运行用户

#2

帖子 poloshiao » 2015-02-09 20:51

但是只有root才能监听80端口
請提供這句話的參考資料網址
rosynirvana
帖子: 893
注册时间: 2011-02-14 17:46

Re: 关于apache的运行用户

#3

帖子 rosynirvana » 2015-02-09 23:29

apache的做法是setuid
poloshiao
论坛版主
帖子: 18279
注册时间: 2009-08-04 16:33

Re: 关于apache的运行用户

#4

帖子 poloshiao » 2015-02-10 9:27

为啥会有三个进程?
參閱
http://unix.stackexchange.com/questions ... ld-var-www
What user should apache and PHP be running as? What permissions should /var/www files have?
wgj
帖子: 294
注册时间: 2007-06-02 20:00

Re: 关于apache的运行用户

#5

帖子 wgj » 2015-02-13 16:47

poloshiao 写了:
但是只有root才能监听80端口
請提供這句話的參考資料網址
可能表述不当。在linux下不是只有以root权限运行的程序才能监听1024以下的端口吗。。
头像
susbarbatus
帖子: 2966
注册时间: 2010-04-10 16:14
系统: Arch Linux

Re: 关于apache的运行用户

#6

帖子 susbarbatus » 2015-02-13 18:01

代码: 全选

ps auxfw | grep apache
root 用户那个是父进程,底下两个 apache 是子进程
沉迷将棋中……
wgj
帖子: 294
注册时间: 2007-06-02 20:00

Re: 关于apache的运行用户

#7

帖子 wgj » 2015-02-13 18:07

It looks like perhaps the first process is as root, maybe from the /etc/init.d/apache script when the system started, and the other ones as www-data spawned from the first. Is that correct?
这个并没有解决我的问题。。。
我的问题是,
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
apache2 2018 root 3u IPv6 16511 0t0 TCP *:http (LISTEN)
apache2 10489 www-data 3u IPv6 16511 0t0 TCP *:http (LISTEN)
apache2 10490 www-data 3u IPv6 16511 0t0 TCP *:http (LISTEN)
这三个进程是如何协作的?
poloshiao
论坛版主
帖子: 18279
注册时间: 2009-08-04 16:33

Re: 关于apache的运行用户

#8

帖子 poloshiao » 2015-02-13 20:32

在linux下不是只有以root权限运行的程序才能监听1024以下的端口吗。。
不完全正確的描述
詳細參閱
http://unix.stackexchange.com/a/16568
Why are the first 1024 ports restricted to the root user only?
On the wide, wild world of the Internet, this doesn't matter.
rosynirvana
帖子: 893
注册时间: 2011-02-14 17:46

Re: 关于apache的运行用户

#9

帖子 rosynirvana » 2015-02-13 21:12

wgj 写了:
poloshiao 写了:
但是只有root才能监听80端口
請提供這句話的參考資料網址
可能表述不当。在linux下不是只有以root权限运行的程序才能监听1024以下的端口吗。。
监听1024以下端口需要特权 -> yes
只有root用户发起的进程才可以监听1024以下端口 -> no

通常解释这个问题时候举的例子是passwd,用户修改自己密码,那就要更新/etc/shadow中的信息,但是一般用户没有这个权限
解决方法是在修改密码时暂时变动程序的uid,有个system call叫setuid可以做到这件事情

同样,apache的做法也是setuid
你看到的三个进程,apache是fork server模型,2个非root权限的进程是实际处理clinet时候的进程
可能这时候有client请求需要处理,也可能是pre-fork出来备用的
rosynirvana
帖子: 893
注册时间: 2011-02-14 17:46

Re: 关于apache的运行用户

#10

帖子 rosynirvana » 2015-02-13 21:18

poloshiao 写了:
在linux下不是只有以root权限运行的程序才能监听1024以下的端口吗。。
不完全正確的描述
詳細參閱
http://unix.stackexchange.com/a/16568
Why are the first 1024 ports restricted to the root user only?
On the wide, wild world of the Internet, this doesn't matter.
您跑题了
楼主的问题是为什么一个非root用户的进程可以监听<1024的端口
使用这些端口确实需要特权的,简单例子

代码: 全选

nc -l 999
会提示权限不足
poloshiao
论坛版主
帖子: 18279
注册时间: 2009-08-04 16:33

Re: 关于apache的运行用户

#11

帖子 poloshiao » 2015-02-13 21:43

但是只有root才能监听80端口
請提供這句話的參考資料網址
在linux下不是只有以root权限运行的程序才能监听1024以下的端口吗。。
不完全正確的描述
詳細參閱
http://unix.stackexchange.com/a/16568
Why are the first 1024 ports restricted to the root user only?
On the wide, wild world of the Internet, this doesn't matter.
您跑题了
楼主的问题是为什么一个非root用户的进程可以监听<1024的端口
1. 我是針對
不是只有以root权限运行的程序才能监听1024以下的端口吗
而提供上面的文章連結

2. 還沒有針對
为什么一个非root用户的进程可以监听<1024的端口
來回覆

3. 造成誤會 特此說抱歉
rosynirvana
帖子: 893
注册时间: 2011-02-14 17:46

Re: 关于apache的运行用户

#12

帖子 rosynirvana » 2015-02-13 22:32

代码: 全选

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char** argv)
{
	int socketfd;
	uid_t ruid;
	struct sockaddr_in servaddr;

	if(argc != 2)
		exit(1);

	if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		perror("socket"), exit(1);
	
	memset(&servaddr, 0, sizeof servaddr);
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(atoi(argv[1]));
	inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

	ruid = getuid();
	if((seteuid(0)) < 0)
		perror("seteuid"), exit(1);
	if((bind(socketfd, (struct sockaddr *)&servaddr, sizeof servaddr)) < 0)
		perror("bind"), exit(1);
	if((seteuid(ruid)) < 0)
		perror("seteuid"), exit(1);
	if((listen(socketfd, 1)) < 0)
		perror("listen"), exit(1);
	
	while(1){
		int connectd_fd;
		int n;
		char buf[4096];
		if((connectd_fd = accept(socketfd, (struct sockaddr *)NULL, NULL))
			< 0)
			perror("connect"), exit(1);
		while((n = recv(connectd_fd, buf, 4096, 0)) > 0){
			buf[n] = '\0';
			puts(buf);
		}
		if(n == 0)
			fprintf(stderr, "%s", "Connection Closed.\n");
		else
			perror("recv"), exit(1);
	}	
	return 0;
}
示例代码,写得比较随意,楼主可以自行研究
1. 端口数大于1024时一切正常
2. 端口数小于1024时,把seteuid的东西注释掉,bind就会报告权限不足
3. 把还原euid的代码注释掉,进程owner就会变成root
4. euid还原后,还是可以正常使用特权端口的
5. 如果不做chown和chmod,seteuid会报告权限不足
编译

代码: 全选

cc foo.c -Wall
sudo chown root:root a.out
sudo chmod +s a.out
apache的做法,以root权限载入一个进程,然后fork出一个,再setuid降低权限等级,于是就安全了,楼主可以自己试着写写看
wgj
帖子: 294
注册时间: 2007-06-02 20:00

Re: 关于apache的运行用户

#13

帖子 wgj » 2015-02-15 21:06

rosynirvana 写了:

代码: 全选

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char** argv)
{
	int socketfd;
	uid_t ruid;
	struct sockaddr_in servaddr;

	if(argc != 2)
		exit(1);

	if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		perror("socket"), exit(1);
	
	memset(&servaddr, 0, sizeof servaddr);
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(atoi(argv[1]));
	inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

	ruid = getuid();
	if((seteuid(0)) < 0)
		perror("seteuid"), exit(1);
	if((bind(socketfd, (struct sockaddr *)&servaddr, sizeof servaddr)) < 0)
		perror("bind"), exit(1);
	if((seteuid(ruid)) < 0)
		perror("seteuid"), exit(1);
	if((listen(socketfd, 1)) < 0)
		perror("listen"), exit(1);
	
	while(1){
		int connectd_fd;
		int n;
		char buf[4096];
		if((connectd_fd = accept(socketfd, (struct sockaddr *)NULL, NULL))
			< 0)
			perror("connect"), exit(1);
		while((n = recv(connectd_fd, buf, 4096, 0)) > 0){
			buf[n] = '\0';
			puts(buf);
		}
		if(n == 0)
			fprintf(stderr, "%s", "Connection Closed.\n");
		else
			perror("recv"), exit(1);
	}	
	return 0;
}
示例代码,写得比较随意,楼主可以自行研究
1. 端口数大于1024时一切正常
2. 端口数小于1024时,把seteuid的东西注释掉,bind就会报告权限不足
3. 把还原euid的代码注释掉,进程owner就会变成root
4. euid还原后,还是可以正常使用特权端口的
5. 如果不做chown和chmod,seteuid会报告权限不足
编译

代码: 全选

cc foo.c -Wall
sudo chown root:root a.out
sudo chmod +s a.out
apache的做法,以root权限载入一个进程,然后fork出一个,再setuid降低权限等级,于是就安全了,楼主可以自己试着写写看
感谢。 :em11
回复