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

311

Pesquisei no Google uma solução há algum tempo, mas não consegui encontrar uma resposta.

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

java.net.BindException: permissão negada: 80

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

Deepak Mittal
fonte
3
Qual é o problema para executar o servidor em outra porta sem privilégios? Você está pensando em algo tão severo quanto desativar o mecanismo de segurança sem fornecer pelo menos um motivo muito sério para executar um servidor nessa porta. O servidor está codificado para conectar-se à porta 80? Se sim, jogue-o fora.
Anônimo
5
possível duplicado de usuário Regular usando portas abaixo de 1024
Roman
4
Você não pode. Portas abaixo de 1024 são privilegiadas e somente o root pode abrir soquetes de escuta nelas. A coisa apropriada a fazer é remover as permissões depois de abri-lo.
Falcon Momot 07/07
2
"Anônimo" - os usuários do mundo foram treinados para procurar determinados serviços em determinadas portas. Em alguns casos, foi padronizado. Por exemplo, HTTP na porta 80 e HTTPS na porta 443. É meio difícil mudar os usuários e padrões do mundo.
1
@FalconMomot Se portas abaixo de 1024 são privilegiadas, por que o servidor Apache não exige uma senha para obter privilégios de root na porta 80, e como eles fazem dessa maneira? Eu acho que o questionador quer saber como fazer as coisas dessa maneira (seja tecnicamente sendo usado como raiz ou não). Fique à vontade para me dizer se estou errado, Deepak Mittal.
Shule 22/08/2015

Respostas:

355

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

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

Executar como root:

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

Como os dispositivos de loopback (como localhost) não usam as regras de pré-roteamento , se você precisar usar o localhost, etc., adicione essa 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ário, pois qualquer usuário pode abrir a porta 8080 (ou qualquer outra porta alta que você decidir usar), interceptando o tráfego. (Créditos ao CesarB ).

EDIT: conforme a pergunta do 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, para excluí-lo:

# iptables -t nat -D PREROUTING 2
Ensolarado
fonte
13
@ Sunny: os votos positivos não são a arma mais rápida do oeste, mas as melhores respostas. O seu é o melhor até agora (mencionei apenas o iptables; você realmente forneceu a linha de comando completa). A única coisa que meu tem o seu não é a advertência sobre outros usuários também ser capaz de se ligar a porta 8080.
CesarB
3
Observe que isso não funciona com o IPv6.
Emmanuel Bourg
3
Alguém poderia explicar como posso remover esta regra mais tarde, quando quiser? Depois de executá-lo, ele funciona, mas aparentemente não é uma "regra" porque não aparece quando eu faço sudo iptables --list. Eu sei o que o iptables é e faz, mas nunca o usei antes disso.
Encoderer
4
Obrigado pela sua resposta ... sempre que eu reiniciar o Ubuntu, essa regra desaparece e tenho que executá-la novamente. Existe uma maneira de salvá-lo para sempre?
Coderji
4
@ Cododerji: verifique a seção "save" na documentação da comunidade: help.ubuntu.com/community/IptablesHowTo
Sunny
79

Use authbind .

Até funciona com Java se você habilitar a pilha somente para IPv4 do Java. Eu uso:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …
geocar
fonte
4
Se o servidor é Tomcat você pode usar authbind automaticamente, definindo AUTHBIND=yesem / etc / default / tomcat6
Emmanuel Bourg
Eu não poderia chegar a este trabalho no servidor Ubuntu com o pacote Java padrão ...
Ashley
Nem eu, alguma solução conhecida?
marca de
10
Observe que você deve configurar authbindpara realmente permitir que isso aconteça. Na página do manual: "/ etc / authbind / byport / port é testado. Se esse arquivo estiver acessível para execução pelo usuário que está chamando, de acordo com o acesso (2), a ligação à porta será autorizada." , por exemplo, para a porta 80 sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80,. A instalação inicial do authbindgeralmente não possui autorizações pré-configuradas.
Jason C
4
Oh nonononononono, nunca chmod 777 nada!
Johannes
57

Se o seu sistema suportar, você poderá usar os recursos. Veja os recursos do 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
Otto Kekäläinen
fonte
isso funciona para o nodejs: setcap 'cap_net_bind_service = + ep' / usr / bin / nodejs
#
5
Este. Eu me pergunto por que essa resposta não tem mais votos positivos. Muito mais fácil do que a opção iptables imho.
Dominik R
5
esta é a resposta correta e mais eficiente, todas as outras respostas causam um impacto no desempenho ou apenas duvidoso / inseguro.
OneOfOne 01/06
41

Outra solução é definir seu aplicativo para que ele possa se conectar à porta 80. Como root, faça o seguinte

chown root ./myapp
chmod +S ./myapp

Lembre-se de que isso, a menos que seja feito da maneira correta, exporá você a possíveis falhas de segurança, porque seu aplicativo estará conversando com a rede e estará executando com privilégios de root completos. Se você usar esta solução, deve procurar o código-fonte do Apache ou Lighttpd ou algo semelhante, onde eles usam os privilégios de root para abrir a porta, mas depois desistem imediatamente desses privs e "se tornam" um usuário com privilégios mais baixos, para que um seqüestrador não pode dominar todo o computador.

Atualização: Como visto nesta pergunta , parece que os kernels do Linux desde 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" recurso. Se você instalar o pacote debian "libcap2-bin", poderá fazê-lo emitindo o comando

setcap 'cap_net_bind_service=+ep' /path/to/program
Paul Tomblin
fonte
6
É o mesmo que executar como root, a menos que o aplicativo saiba descartar privilégios.
CesarB
14
Isso é perigoso. Isso significa que qualquer solicitação será executada como raiz. É por uma razão que até o apache inicia como root para vincular e depois descarta os privilégios para outro usuário.
Ensolarado
9
Paul: o iptables não é tão perigoso, porque mesmo que o aplicativo seja comprometido, ele não expõe o sistema a ataques, pelo menos não com privilégios de root. A execução do aplicativo como root é outra história.
Ensolarado
1
O perigo para o iptables é apenas se este for um sistema multiusuário, como disse CesarB, pois qualquer pessoa pode se conectar ao 8080 e interceptar o tráfego.
Ensolarado
1
lol, amo como a resposta aceita tem uma -15
Evan Teran
40

Eu simplesmente uso o Nginx na frente. Também pode ser executado no localhost.

  • apt-get install nginx

.. ou ..

  • pkg_add -r nginx

.. ou o que for mais adequado ao seu sistema operacional.

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

servidor {
        ouça 80;
        server_name some.domain.org;
        local / {
            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;
        }
}
CosmicB
fonte
Eu realmente gosto desta solução.
Thomasfedb 6/12/12
1
Este é (uma das) a solução sugerida de JFrog si: jfrog.com/confluence/display/RTF/nginx
stolsvik
36

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 puder 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, suponha que nosso servidor decida redirecionar o usuário de uma página HTTP para uma página HTTPS. A menos que reescrevamos cuidadosamente a resposta, ela seria redirecionada para https://host:8181/. Neste ponto, estamos ferrados:

  • Alguns usuários marcariam o https://host:8181/URL como favorito e precisaríamos mantê-lo para evitar a quebra de 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 impede que os usuários se conectem diretamente às portas 8080, 8181

Misha
fonte
1
Isso é bom, mas por que não vincular o daemon ao localhost: 8080 em vez de 0.0.0.0:8080? Eu quero fazer isso, mas preciso das tabelas de ip para isso.
Amala 15/12
Funciona, muito legal.
Xtian #
29

Tradicionalmente, no Unix, apenas o root pode ligar-se 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. Observe que, com isso, você perde a proteção extra do portas baixas; qualquer usuário em sua máquina pode se conectar à porta 8080.

CesarB
fonte
23

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

WMR
fonte
1
eles funcionam, eu uso o CAP_NET_RAW para executar ferramentas como o tcpdump como um usuário normal.
23710 Justin Justin
12

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

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

  • Balanceamento de carga
  • Reiniciando seus servidores de aplicativos com usuários recebendo uma página de erro sofisticada
  • Acelere as coisas com cache
  • Configurações refinadas que você normalmente faz com um proxy reverso e não com um servidor de aplicativos
Giovanni Toraldo
fonte
6

Você pode usar o programa de redirecionamento:

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1
user340994
fonte
4

Use sudo.

Configure o sudo para que o usuário comum possa executar 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 em particular)

Agora não
fonte
8
Isso tem o mesmo problema - executar um serviço como root é uma prática ruim.
22640 Kevin Panko
4

a resposta de sunny está correta, mas você pode enfrentar problemas adicionais, pois a interface de loopback não usa a tabela PREROUTING,

então as regras do iptables a serem adicionadas 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
Francesco
fonte
3

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

Ambas as extensões do kernel 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.

Aaron Digulla
fonte
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 à 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.


fonte
2

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

A maneira como algo como o Apache faz isso (liga-se à porta 80, mas está sendo executada como alguém que não é root) é executar como root, vincular-se à porta e alterar a propriedade do processo para o usuário não privilegiado após a porta está configurado. Se o aplicativo que você está escrevendo pode ser executado pela raiz, você pode alterar o proprietário para o usuário não privado após a instalação das portas. Mas se for apenas para um usuário comum executar a partir da linha de comando, será necessário usar uma das outras soluções.

rjray
fonte
2

Quando tenho vários aplicativos de serviço da web (scripts python, mecanismos 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.

Na configuração do apache: s:

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

Consulte a documentação do mod-proxy para obter mais informações: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html


fonte
1
A desvantagem desta solução é a perda do IP recebido nos logs do Tomcat.
Emmanuel Bourg
2

Acho que a melhor solução é sgid seu aplicativo e, assim que tiver sua porta vinculada, ele deverá perder os privilégios alternando para outro usuário.

Anxy Dicy
fonte
1

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

E 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

http://docs.codehaus.org/display/JETTY/port80 explica melhor.

Thomas
fonte
1
Isso é basicamente equivalente a colocar um proxy reverso na frente do servidor, mas é bastante ineficiente em comparação com soluções dedicadas como HAproxy, Pound ou Varnish que entendem o protocolo HTTP e podem adicionar cabeçalhos úteis, como o X-Forwarded-For.
Emmanuel Bourg
-1

Além disso, o FreeBSD e o Solaris (alguém se lembra dessa ?) Permitem fazer isso (vincular-se a portas baixas) sem escalonamento de privilégios (ou seja, usar programas para mudar para o root). Desde que você especificou o Linux, estou postando isso como um aviso para outras pessoas que possam encontrar essa pergunta.

Daniel C. Sobral
fonte
-1

Necromante.

Simples. Com um kernel normal ou antigo, você não.
Como apontado por outros, o iptables pode encaminhar uma porta.
Como também apontado por outros, CAP_NET_BIND_SERVICE também pode fazer o trabalho.
É claro que CAP_NET_BIND_SERVICE falhará se você iniciar o programa a partir de um script, a menos que defina o limite no interpretador de shell, o que não faz sentido, você poderá executar o serviço como root ...
por exemplo, para Java, você deve aplicá-lo para a JAV JVM

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.

Também tenho certeza de que o xinetd não é a melhor das idéias.
Mas como os dois métodos são hacks, por que não apenas elevar o limite, elevando a restrição?
Ninguém disse que você precisa rodar um kernel normal, então você pode rodar o seu próprio.

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

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

Lá você procura 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 ssh insegura, altere-a para o seguinte: #define PROT_SOCK 24

Geralmente, eu usaria a configuração mais baixa que você precisa, por exemplo, 79 para http ou 24 ao usar 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.

Aqui está como você compila um kernel:

https://help.ubuntu.com/community/Kernel/Compile

# 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 quiser permanecer seguro, compile o kernel se quiser ter certeza de que essa restrição nunca mais o incomoda.

Dilema
fonte
Alguém poderia explicar os votos negativos? A compilação do kernel não está funcionando? Ou é apenas porque depois, você não pode mais fazer uma atualização do kernel a partir dos repositórios normais?
dilema
Eu tentei esta solução ( sudo setcap cap_net_bind_service=+ep /path-to-java/java), mas sempre recebo java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directoryse o java tiver caps definido. ver também a primeira parte do unix.stackexchange.com/a/16670/55508
Daniel Alder
1
Resolvido o erro anterior, adicionando <javahome>/lib/amd64/jli/a ld.so.confe corridasudo ldconfig
Daniel Alder