Como executar um servidor na porta 80 como um usuário normal no Linux?

283

Eu pesquisei sobre isso por algum tempo, mas não consegui encontrá-lo.

Estou no Ubuntu Linux e quero rodar um servidor na porta 80, mas devido ao mecanismo de segurança do Ubuntu, recebo o seguinte erro:

java.net.BindException: Permission denied:80

Eu acho que deve ser simples o suficiente para desativar este mecanismo de segurança para que a porta 80 esteja disponível para todos os usuários ou para atribuir os privilégios necessários ao usuário atual para acessar a porta 80.

    
por Deepak Mittal 10.11.2008 / 15:31

20 respostas

332

Resposta curta: você não pode. Portas abaixo de 1024 podem ser abertas apenas pelo root. Como comentário - bem, você pode, usando CAP_NET_BIND_SERVICE , mas essa abordagem, aplicada ao java bin fará com que qualquer programa java ser executado com essa configuração, o que é indesejável, se não for um risco de segurança.

A resposta longa: você pode redirecionar as conexões na porta 80 para alguma outra porta que você possa abrir como usuário normal.

Executar como root:

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

Como dispositivos loopback (como localhost) não usam as regras de pré-formatação, se você precisar usar localhost, etc., inclua esta regra também ( obrigado @Francesco ):

# iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

NOTA: A solução acima não é adequada para sistemas multiusuários, pois qualquer usuário pode abrir a porta 8080 (ou qualquer outra porta alta que você decida usar), interceptando o tráfego. (Créditos para CesarB ).

EDIT: como por questão de comentário - para excluir a regra acima:

# iptables -t nat --line-numbers -n -L

Isso produzirá algo como:

Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:8080 redir ports 8088
2    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 redir ports 8080

A regra em que você está interessado é nr. 2, portanto, para excluí-lo:

# iptables -t nat -D PREROUTING 2
    
por 10.11.2008 / 15:41
78

Use authbind .

Ele também funciona com Java se você ativar a pilha somente do IPv4 do Java. Eu uso:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …
    
por 14.11.2008 / 14:12
46

Se o seu sistema suportar, talvez você possa usar recursos. Veja capacidades de homem, o que você precisa seria CAP_NET_BIND_SERVICE.

No Debian / Ubuntu mais recente você pode executar:

sudo apt-get install libcap2-bin 
sudo setcap 'cap_net_bind_service=+ep' /path/to/program
    
por 30.05.2012 / 22:32
39

Outra solução é tornar seu aplicativo setuid para que ele possa ligar com a porta 80. Como root, faça o seguinte

chown root ./myapp
chmod +S ./myapp

Lembre-se de que, a menos que esteja absolutamente correto, você ficará exposto a potenciais brechas de segurança, pois seu aplicativo estará falando com a rede e executando com privilégios de raiz completos. Se você tomar esta solução, você deve olhar para o código-fonte do Apache ou Lighttpd ou algo semelhante, onde eles usam os privilégios de root para abrir a porta, mas imediatamente desistir desses privs e "tornar-se" um usuário com menos privilégios para que um sequestrador não pode controlar todo o seu computador.

Atualização: conforme visto em essa questão , parece que os kernels Linux desde o 2.6.24 têm um novo recurso que permite marcar um executável (mas não um script, é claro) como tendo o" CAP_NET_BIND_SERVICE "capacidade. Se você instalar o pacote debian "libcap2-bin", você pode fazer isso emitindo o comando

setcap 'cap_net_bind_service=+ep' /path/to/program
    
por 10.11.2008 / 15:44
35

Abordagem proposta por Sunny e CesarB:

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

funciona bem, mas tem uma pequena desvantagem - não impede que o usuário se conecte diretamente à porta 8080 em vez de 80.

Considere o seguinte cenário quando isso pode ser um problema.

Digamos que temos um servidor que aceita conexões HTTP na porta 8080 e conexões HTTPS na porta 8181.

Usamos o iptables para estabelecer os seguintes redirecionamentos:

80  ---> 8080
443 ---> 8181

Agora, vamos supor que nosso servidor decida redirecionar o usuário de uma página HTTP para uma página HTTPS. A menos que cuidadosamente reescrevêssemos a resposta, ela seria redirecionada para https://host:8181/ . Neste ponto, estamos ferrados:

  • Alguns usuários marcariam o URL https://host:8181/ e precisaríamos manter esse URL para evitar que eles quebrassem seus favoritos.
  • Outros usuários não poderiam se conectar porque seus servidores proxy não suportam portas SSL não padrão.

Eu uso a seguinte abordagem:

iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp --dport 443 -j MARK --set-mark 1
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8181
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -m mark --mark 1 -j ACCEPT
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8181 -m mark --mark 1 -j ACCEPT

Combinado com a regra REJECT padrão na cadeia INPUT, essa abordagem evita que os usuários se conectem diretamente às portas 8080, 8181

    
por 20.02.2010 / 17:19
35

Eu simplesmente uso o Nginx na frente. Ele pode ser executado no host local também.

  • apt-get install nginx

.. ou ..

  • pkg_add -r nginx

.. ou o que for melhor para o seu sistema operacional.

Tudo o que você precisa no nginx.conf, se estiver executando em localhost, é:

server {
        listen  80;
        server_name some.domain.org;
        location / {
            proxy_set_header    Host $host;
            proxy_set_header    X-Real-IP   $remote_addr;
            proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass  http://127.0.0.1:8081;
        }
}
    
por 20.11.2012 / 15:30
29

Tradicionalmente, no Unix, somente o root pode se ligar a portas baixas (< 1024).

A maneira mais simples de contornar isso é executar o servidor em uma porta alta (por exemplo, 8080) e usar uma regra iptables simples para encaminhar as conexões da porta 80 para a porta 8080. Nota que com isso você perde a proteção extra das portas baixas; qualquer usuário em sua máquina pode ligar à porta 8080.

    
por 10.11.2008 / 15:36
23

Se o seu sistema suportar, talvez você possa usar recursos. Veja man capabilities , o que você precisa seria CAP_NET_BIND_SERVICE . Não, eu nunca usei eles e não sei se eles realmente funcionam: -)

    
por 10.11.2008 / 17:27
11

Use um proxy reverso (nginx, apache + mod_proxy) ou um proxy reverso de armazenamento em cache (Squid, Varnish) na frente de seus servidores de aplicativos!

Com um proxy reverso, você pode conseguir muitas coisas interessantes como:

  • Equilíbrio de carga
  • Reiniciando seus servidores de aplicativos com usuários recebendo uma página de erro sofisticada
  • Acelere as coisas com o cache
  • Configurações refinadas que você normalmente faz com um proxy reverso e não com um servidor de aplicativos
por 18.10.2011 / 17:36
6

Você pode usar o programa de redirecionamento:

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1
    
por 27.11.2012 / 13:48
4

Use o sudo.

Configure o sudo para que o usuário comum possa executar os comandos apropriados:

/etc/init.d/httpd start

Ou

apachectl stop

Ou

/usr/local/apache2/apachectl restart

Ou

/myapp/myappbin start

(Ou qualquer outro comando / script usado para iniciar / parar seu servidor / aplicativo específico)

    
por 10.11.2008 / 20:40
4

resposta de ensolarado está correta, mas você pode enfrentar problemas adicionais como interface de loopback não use a tabela PREROUTING,

então as regras do iptables para adicionar são duas:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080
    
por 31.01.2013 / 17:41
3

Com o Linux, você tem outras duas opções:

  • Você pode experimentar o SELinux ( link )
  • Você pode experimentar o grsecurity ( link )

As duas extensões para o kernel do Linux permitem conceder direitos de acesso em um nível muito refinado. Isso permitiria que você concedesse esse processo para abrir a porta 80, mas não herdaria nenhum dos outros direitos de root.

Pelo que ouvi, o grsecurity é muito mais simples de usar, mas o SELinux é mais seguro.

    
por 11.11.2008 / 09:27
2

Uma solução é usar o iptables para executar o PAT em pacotes para a porta 80. Você pode usar isso para rotear os pacotes para a porta local 8080, por exemplo. Certifique-se e ajuste os pacotes de saída de volta para a porta 80.

Na minha experiência, os recursos de permissões refinadas do Linux não são compilados em kernels padrão devido a problemas de segurança.

    
por 10.11.2008 / 15:36
2

Se você estiver tentando fazer isso para que um comando de execução do usuário possa usar a porta 80, suas únicas soluções são os truques iptables ou a configuração do executável setuid-to-root.

A forma como o Apache faz isso (ele se liga à porta 80, mas está sendo executado como outra pessoa além do root) é executar como root, vincular-se à porta e alterar a propriedade do processo para o usuário não privilegiado. após a porta ser configurada. Se o aplicativo que você está escrevendo puder ser executado pelo root, você poderá fazê-lo alterar o proprietário para o usuário não privado depois que as portas estiverem configuradas. Mas se isso é apenas para um usuário médio para executar a partir da linha de comando, então você terá que usar uma das outras soluções.

    
por 11.11.2008 / 00:57
2

Quando tenho vários aplicativos de serviço da web (scripts python, mecanismos do tomcat, ...) que não quero executar como root, geralmente configuro um servidor da web apache na frente deles. O Apache escuta a porta 80 e o tomcat escuta 8080.

No apache: s config:

ProxyPass /webapp http://localhost:8080/webapp
ProxyPassReverse /webapp http://localhost:8080/webapp

Veja a documentação do mod-proxy para mais informações: link

    
por 12.11.2008 / 10:58
2

Acho que a melhor solução é colocar o seu aplicativo e, assim que ele tiver seu limite de porta, ele deverá eliminar os privilégios trocando para outro usuário.

    
por 18.10.2011 / 17:31
1

Alguns sistemas host não estão permitindo o uso do módulo NAT, o 'iptables' não resolve o problema neste caso.

Que tal o xinetd?

No meu caso (Ubuntu 10.04)

# apt-get install xinetd
# touch /etc/xinetd.d/my_redirect
# vim /etc/xinetd.d/my_redirect

Cole a configuração:

service my_redirector_80
{
 disable = no
 socket_type = stream
 protocol = tcp
 user = root
 wait = no
 port = 80
 redirect = localhost 8080
 type = UNLISTED
}

Então:

# service xinetd restart
O

link explica melhor.

    
por 10.02.2012 / 15:33
0

Como um aparte, o FreeBSD e o Solaris (qualquer um lembra que um?) permite fazer isso (ligar a portas baixas) sem escalonamento de privilégios (ou seja, usando programas para mudar para root). Desde que você especificou o Linux, eu estou apenas postando isso como um aviso para outras pessoas que possam encontrar esta questão.

    
por 06.02.2012 / 15:48
-1

Necromancing.

Simples. Com um kernel normal ou antigo, você não faz isso.
Como apontado por outros, o iptables pode encaminhar uma porta.
Como também apontado por outros, o CAP_NET_BIND_SERVICE também pode fazer o trabalho.
Claro CAP_NET_BIND_SERVICE falhará se você iniciar o seu programa a partir de um script, a menos que você defina o limite no interpretador de shell, o que é inútil, você poderia também executar o seu serviço como root ...
por exemplo. para Java, você tem que aplicá-lo à JVM JAVA

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java

Obviamente, isso significa que qualquer programa Java pode ligar portas do sistema.
Dito para mono / .NET.

Eu também tenho certeza que xinetd não é a melhor das idéias.
Mas como ambos os métodos são hacks, por que não apenas levantar o limite levantando a restrição?
Ninguém disse que você tem que rodar um kernel normal, então você pode simplesmente rodar o seu próprio kernel.

Você acabou de baixar a fonte do kernel mais recente (ou o mesmo que você tem atualmente). Depois, você vai para:

/usr/src/linux-<version_number>/include/net/sock.h:

Lá você procura por esta linha

/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK       1024

e mude para

#define PROT_SOCK 0

se você não quiser ter uma situação de ssh insegura, altere para isto:     #define PROT_SOCK 24

Geralmente, eu usaria a configuração mais baixa de que você precisa, por exemplo, 79 para http ou 24 ao usar o SMTP na porta 25.

Isso já é tudo.
Compile o kernel e instale-o.
Reinicie.
Concluído - esse limite estúpido é GONE, e isso também funciona para scripts.

Veja como você compila um kernel:

link

# You can get the kernel-source via package linux-source, no manual download required
apt-get install linux-source fakeroot

mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>

# Apply the changes to PROT_SOCK define in /include/net/sock.h

# Copy the kernel config file you are currently using
cp -vi /boot/config-'uname -r' .config

# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev

# Run menuconfig (optional)
make menuconfig

# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers

# And wait a long long time

cd ..
Em poucas palavras, use o iptables se você quer ficar seguro, compile o kernel se você quer ter certeza de que essa restrição nunca o incomoda novamente.

    
por 16.01.2015 / 18:04

Tags