分页: 1 / 1

关于apache的运行用户

发表于 : 2015-02-09 20:46
wgj
一般来说为了安全着想,运行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

Re: 关于apache的运行用户

发表于 : 2015-02-09 20:51
poloshiao
但是只有root才能监听80端口
請提供這句話的參考資料網址

Re: 关于apache的运行用户

发表于 : 2015-02-09 23:29
rosynirvana
apache的做法是setuid

Re: 关于apache的运行用户

发表于 : 2015-02-10 9:27
poloshiao
为啥会有三个进程?
參閱
http://unix.stackexchange.com/questions ... ld-var-www
What user should apache and PHP be running as? What permissions should /var/www files have?

Re: 关于apache的运行用户

发表于 : 2015-02-13 16:47
wgj
poloshiao 写了:
但是只有root才能监听80端口
請提供這句話的參考資料網址
可能表述不当。在linux下不是只有以root权限运行的程序才能监听1024以下的端口吗。。

Re: 关于apache的运行用户

发表于 : 2015-02-13 18:01
susbarbatus

代码: 全选

ps auxfw | grep apache
root 用户那个是父进程,底下两个 apache 是子进程

Re: 关于apache的运行用户

发表于 : 2015-02-13 18:07
wgj
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)
这三个进程是如何协作的?

Re: 关于apache的运行用户

发表于 : 2015-02-13 20:32
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.

Re: 关于apache的运行用户

发表于 : 2015-02-13 21:12
rosynirvana
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出来备用的

Re: 关于apache的运行用户

发表于 : 2015-02-13 21:18
rosynirvana
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
会提示权限不足

Re: 关于apache的运行用户

发表于 : 2015-02-13 21:43
poloshiao
但是只有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. 造成誤會 特此說抱歉

Re: 关于apache的运行用户

发表于 : 2015-02-13 22:32
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降低权限等级,于是就安全了,楼主可以自己试着写写看

Re: 关于apache的运行用户

发表于 : 2015-02-15 21:06
wgj
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