Permitindo que um usuário ouça uma porta abaixo de 1024

63

Eu preciso permitir que um usuário (diferente da raiz) execute um servidor que esteja escutando na porta 80.

Há alguma maneira de fazer isso?

peoro
fonte
11
Esta questão está aberta à interpretação. Espero que você queira dizer "você criou um novo serviço de sistema que você (como root) gostaria de executar em uma conta não privilegiada por razões de segurança" (considerada uma boa prática) e não "Tenho um usuário ao qual é perguntado se pode executar seu próprio servidor da web no meu sistema, como permito que eles acessem? " (prática considerada bastante pobre)
Michael Shaw
3
@Ptolemy, o motivo real é: minha máquina está atrás de um firewall que bloqueia qualquer porta, exceto a 80. Quero hospedar um servidor (que não reduz privilégios!), Portanto, preciso ouvi-la na porta 80, mas não confie que ele seja executado como root (por razões óbvias de segurança). Estou autorizado a fazer isso, se você se importa.
peoro 06/04
serverfault.com/questions/112795/…
Ciro Santilli escreveu:

Respostas:

50

setcap 'cap_net_bind_service=+ep' /path/to/program

isso funcionará para processos específicos. Mas, para permitir que um usuário em particular se ligue a portas abaixo de 1024, será necessário adicioná-lo aos sudoers.

Dê uma olhada nesta discussão para saber mais.

Rohan Monga
fonte
31

(Alguns desses métodos foram mencionados em outras respostas; estou dando várias opções possíveis em ordem aproximada de preferência.)

Você pode redirecionar a porta baixa para uma porta alta e ouvir na porta alta.

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 1080

Você pode iniciar o servidor como root e remover privilégios depois de começar a escutar na porta privilegiada. De preferência, em vez de codificar você mesmo, inicie o servidor a partir de um wrapper que faça o trabalho para você. Se o servidor iniciar uma instância por conexão, inicie-a em inetd(ou em um programa semelhante como xinetd). Para inetd, use uma linha como esta em /etc/inetd.conf:

http  stream  tcp  nowait  username:groupname  /path/to/server/executable  argv[0] argv[1]…

Se o servidor ouvir em uma única instância, inicie-o em um programa como authbind. Crie um arquivo vazio /etc/authbind/byport/80e torne-o executável para o usuário que está executando o servidor; ou create /etc/authbind/byuid/1234, onde 1234 é o UID executando o servidor, contendo a linha 0.0.0.0/0:80,80.

Se o seu executável do servidor é armazenado em um sistema de arquivos que suporta capacidades, você pode dar-lhe a capacidade . Cuidado que os recursos ainda são relativamente novos e ainda têm algumas distorções .cap_net_bind_service

setcap cap_net_bind_service=ep /path/to/server/executable
Gilles 'SO- parar de ser mau'
fonte
4
Em todos os casos com os quais tive que lidar, o executável era um script que lançava java ou python. Como um cara sem 10 horas para gastar nos bons pontos, sua solução do iptables cobre tudo sem problemas.
srking 22/03/12
Para a solução iptables, eu também precisei adicionar uma regra de filtro, -A INPUT -p tcp --dport 1080 -j ACCEPTcaso contrário não funcionaria (também tenho um -j DROPcatch-all). Portanto, fico com dois soquetes de escuta.
thom_nic
4

A resposta curta é que isso não é possível por design.

A resposta longa é que, nos mundos de código aberto, há muitas pessoas brincando com o design e criando métodos alternativos. Em geral, é amplamente aceito que isso não deve ser possível. O fato de você estar tentando provavelmente significa que você tem outra falha de design em seu sistema e deve reconsiderar toda a arquitetura do sistema à luz das melhores práticas * nix e implicações de segurança.

Dito isto, um programa para autorizar o acesso não raiz a portas baixas é o authbind . Tanto o selinux quanto o grsecurity também fornecem estruturas para essas autenticações ajustadas.

Por fim, se você deseja que usuários específicos executem programas específicos como root e o que você realmente precisa é apenas para permitir que um usuário reinicie o apache ou algo parecido, sudoé seu amigo!

Caleb
fonte
8
A "segurança" do porto não dá muito para você no mundo moderno.
Pjc50
3
@ pjc50: Sim, sim. É sobre confiança implícita. Números de porta baixos implicam alta confiança. Espera-se que SSH, POP, FTP e outros daemons solicitem senhas no nível do sistema e outras credenciais quando suas portas forem abertas. Se os usuários tiverem permissão para escutar em portas baixas em uma caixa, eles poderão iniciar daemons falsos em portas não utilizadas (ou com falha) e coletar senhas de usuários inocentes. Essas senhas poderiam então ser usadas nessa caixa para comprometer outras contas, incluindo raiz.
Caleb
8
Essa é uma forma muito fraca de segurança. Se você se conectou a algo e não fez uma transação de certificado, não tem idéia de com quem está falando - ou seja, ataques MITM.
Pjc50
5
Suponho que seja necessário chown para ports: então você pode "chown mail port25" e (a) seu daemon de email não precisa ser iniciado com privs raiz e (b) ninguém mais pode sequestrá-lo.
Pjc50
7
Embora isso possa ter sido verdade "por design" quando o linux estava em sua infância, faz muito pouco sentido naquela época e agora. Segurança tem tudo a ver com o que um usuário pode ou não fazer. Permitir que apenas o usuário root use a porta 80, por exemplo, é um enorme risco de segurança, pois significa que você precisa conceder acesso root a pessoas que precisam usar a porta 80, mas não devem ter acesso root. Se você confiar no usuário não raiz X para usar a porta 80, poderá codificar essa confiança no seu sistema operacional. Felizmente, como você mencionou, existem soluções de baixa qualidade que permitem isso, como o authbind.
BT
3

Você pode usar o encaminhamento de porta netcat ou xinetd ou iptables ou usar o apache como proxy de front-end e executar o processo em uma porta não privilegiada.

jamespo
fonte
3

Authbind , o @Gilles já mencionou, mas gostaria de expandir um pouco.

Possui controle de acesso conveniente (detalhes na página de manual): você pode filtrar o acesso por porta, endereço de interface, uid, intervalos de endereço ou porta e combinação destes.

Tem parâmetro muito útil --depth:

--depth níveis

Faz com que o authbind afete programas com níveis profundos no gráfico de chamada. O padrão é 1.

"Níveis profundos" significa que quando um script (ou programa) executa outro script, ele desce um nível. Portanto, se você possui os --depth 5níveis 1 (ou 0?) A 5, você tem permissão para vincular, enquanto no nível 6 e posterior, não. Útil quando você deseja que um script tenha acesso, mas não programas executados com ou sem o seu conhecimento.


Para ilustrar, você pode ter algo parecido com isto: por uma questão de segurança, você tem um usuário javaque deve executar apenas java e deseja dar a ele acesso à porta 80:

echo > /etc/authbind/byport/80
chown root:java /etc/authbind/byport/80
chmod 710 /etc/authbind/byport/80

Eu criei o ../byport/80 file, entreguei ao javagrupo de usuários (cada usuário tem seu próprio grupo) e o tornei executável por grupo, o que significa que é executável por javausuário. Se você está dando acesso por porta, o arquivo deve ser executável pelo usuário que deve ter acesso, então fizemos isso.

Isso pode ser suficiente para o Joe médio, mas como você sabe usar o --depthparâmetro, você executa (como javausuário) authbind --depth [depth] my_web_app's_start_scriptiniciando --depth 1e trabalhando até encontrar a menor profundidade que funcione e a use.

Leia a página de manual para mais detalhes .

Dominykas Mostauskis
fonte
1

Tentei o método iptables PREROUTING REDIRECT, mas descobri que ele também afeta pacotes encaminhados. Ou seja, se a máquina também estiver encaminhando pacotes entre interfaces (por exemplo, se estiver atuando como um ponto de acesso Wi-Fi conectado a uma rede Ethernet), a regra iptables também capturará as conexões dos clientes conectados aos destinos da Internet e as redirecionará para a máquina. Não era isso que eu queria; eu só queria redirecionar as conexões direcionadas à própria máquina.

Uma possibilidade é usar o encaminhamento de porta TCP. Por exemplo, usando socat:

socat TCP4-LISTEN:www,reuseaddr,fork TCP4:localhost:8080

No entanto, uma desvantagem desse método é que o aplicativo que está escutando na porta 8080 não conhece o endereço de origem das conexões de entrada (por exemplo, para log ou outros fins de identificação).

Craig McQueen
fonte