web-dev-qa-db-fra.com

Comment exécuter un serveur sur le port 80 en tant qu'utilisateur normal sous Linux?

Je recherche une solution sur Google depuis un certain temps, mais je n'ai pas trouvé de réponse.

Je suis sur Ubuntu Linux et je veux exécuter un serveur sur le port 80, mais en raison du mécanisme de sécurité d'Ubuntu, j'obtiens l'erreur suivante:

Java.net.BindException: autorisation refusée: 80

Je pense qu'il devrait être assez simple de désactiver ce mécanisme de sécurité afin que le port 80 soit disponible pour tous les utilisateurs ou d'attribuer les privilèges requis à l'utilisateur actuel pour accéder au port 80.

324
Deepak Mittal

Réponse courte: vous ne pouvez pas. Les ports inférieurs à 1024 ne peuvent être ouverts que par root. Selon le commentaire - eh bien, vous pouvez, en utilisant CAP_NET_BIND_SERVICE , mais cette approche, appliquée à Java bin fera n'importe quel programme Java Java à exécuter avec ce paramètre, ce qui est indésirable, sinon un risque pour la sécurité.

La réponse longue: vous pouvez rediriger les connexions sur le port 80 vers un autre port que vous pouvez ouvrir en tant qu'utilisateur normal.

Exécuter en tant que root:

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

Comme les périphériques de bouclage (comme localhost) n'utilisent pas les règles de pré-routage, si vous devez utiliser localhost, etc., ajoutez également cette règle ( merci @Francesco ):

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

REMARQUE: La solution ci-dessus n'est pas bien adaptée aux systèmes multi-utilisateurs, car tout utilisateur peut ouvrir le port 8080 (ou tout autre port haut que vous décidez d'utiliser) ), interceptant ainsi le trafic. (Crédits à CesarB ).

EDIT: selon la question de commentaire - pour supprimer la règle ci-dessus:

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

Cela produira quelque chose comme:

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

La règle qui vous intéresse est nr. 2, donc pour le supprimer:

# iptables -t nat -D PREROUTING 2
366
Sunny

Utilisez authbind .

Il fonctionne même avec Java si vous activez la pile IPv4 uniquement de Java. J'utilise:

authbind --deep $Java_HOME/bin/Java -Djava.net.preferIPv4Stack=true …
81
geocar

Si votre système le prend en charge, vous pouvez peut-être utiliser des fonctionnalités. Voir les capacités de l'homme, celle dont vous avez besoin serait CAP_NET_BIND_SERVICE.

Sur les versions plus récentes de Debian/Ubuntu, vous pouvez exécuter:

Sudo apt-get install libcap2-bin 
Sudo setcap 'cap_net_bind_service=+ep' /path/to/program
60

Une autre solution consiste à configurer votre application afin qu'elle puisse se lier au port 80. En tant que root, procédez comme suit

chown root ./myapp
chmod +S ./myapp

Gardez à l'esprit que cela, à moins que cela ne soit absolument parfait, vous exposera à des failles de sécurité potentielles, car votre application parlera au réseau et s'exécutera avec les privilèges root complets. Si vous prenez cette solution, vous devriez regarder le code source d'Apache ou de Lighttpd ou quelque chose de similaire, où ils utilisent les privilèges root pour ouvrir le port, mais abandonner immédiatement ces privilèges et "devenir" un utilisateur privilégié inférieur afin que un pirate de l'air ne peut pas prendre le contrôle de tout votre ordinateur.

Mise à jour: comme vu dans cette question , il semble que les noyaux Linux depuis 2.6.24 ont une nouvelle capacité qui vous permet de marquer un exécutable (mais pas un script, bien sûr) comme ayant le "CAP_NET_BIND_SERVICE ". Si vous installez le paquet Debian" libcap2-bin ", vous pouvez le faire en exécutant la commande

setcap 'cap_net_bind_service=+ep' /path/to/program
42
Paul Tomblin

J'utilise simplement Nginx devant. Il peut également fonctionner sur localhost.

  • apt-get install nginx

.. ou ..

  • pkg_add -r nginx

.. ou ce qui convient à votre système d'exploitation.

Tout ce dont vous avez besoin dans nginx.conf, s'il fonctionne sur localhost, est:

 serveur {
 écouter 80; 
 nom_serveur some.domain.org; 
 emplacement/{
 proxy_set_header Hôte $ Hôte; 
 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;
} 
 } 
41
CosmicB

Approche proposée par Sunny et CesarB:

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

fonctionne bien mais il a un petit inconvénient - il n'empêche pas l'utilisateur de se connecter directement au port 8080 au lieu de 80.

Considérez le scénario suivant lorsque cela peut être un problème.

Disons que nous avons un serveur qui accepte les connexions HTTP sur le port 8080 et les connexions HTTPS sur le port 8181.

Nous utilisons iptables pour établir les redirections suivantes:

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

Supposons maintenant que notre serveur décide de rediriger l'utilisateur d'une page HTTP vers une page HTTPS. Si nous ne réécrivons pas soigneusement la réponse, elle serait redirigée vers https://Host:8181/. À ce stade, nous sommes foutus:

  • Certains utilisateurs mettent en signet le https://Host:8181/ URL et nous devons conserver cette URL pour éviter de casser leurs signets.
  • Les autres utilisateurs ne pourraient pas se connecter car leurs serveurs proxy ne prennent pas en charge les ports SSL non standard.

J'utilise l'approche suivante:

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

Combinée avec la règle REJECT par défaut sur la chaîne INPUT, cette approche empêche les utilisateurs de se connecter directement aux ports 8080, 8181

36
Misha

Traditionnellement sous Unix, seule la racine peut se lier aux ports bas (<1024).

La façon la plus simple de contourner ce problème est d'exécuter votre serveur sur un port élevé (par exemple, 8080) et d'utiliser une règle iptables simple pour transférer les connexions du port 80 au port 8080. Notez qu'avec cette vous perdez la protection supplémentaire des ports bas; n'importe quel utilisateur de votre machine peut se connecter au port 8080.

29
CesarB

Si votre système le prend en charge, vous pouvez peut-être utiliser des fonctionnalités. Voir man capabilities, celui dont vous avez besoin serait CAP_NET_BIND_SERVICE. Non, je ne les ai jamais utilisés moi-même et je ne sais pas s'ils fonctionnent vraiment :-)

23
WMR

Utilisez un proxy inverse (nginx, Apache + mod_proxy) ou un proxy inverse de mise en cache (Squid, Varnish) devant vos serveurs d'applications!

Avec un proxy inverse, vous pouvez réaliser beaucoup de choses intéressantes comme:

  • L'équilibrage de charge
  • Redémarrage de vos serveurs d'applications avec des utilisateurs recevant une page d'erreur fantaisie
  • Accélérez les choses avec le cache
  • Paramètres précis que vous faites normalement avec un proxy inverse et non avec un serveur d'applications
12
Giovanni Toraldo

Vous pouvez utiliser le programme redir:

Sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1
6
user340994

la réponse de sunny est correcte, mais vous pouvez rencontrer des problèmes supplémentaires car l'interface de bouclage n'utilise pas la table PREROUTING,

donc les règles iptables à ajouter sont deux:

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
4
Francesco

Utilisez Sudo.

Configurez Sudo pour que l'utilisateur ordinaire puisse exécuter les commandes appropriées:

/etc/init.d/httpd start

Ou

apachectl stop

Ou

/usr/local/Apache2/apachectl restart

Ou

/myapp/myappbin start

(Ou toute autre commande/script que vous utilisez pour démarrer/arrêter votre serveur/application en particulier)

4
Not Now

Avec Linux, vous avez deux autres options:

Les deux extensions du noyau Linux permettent d'accorder des droits d'accès à un niveau très fin. Cela vous permettrait d'accorder ce processus pour ouvrir le port 80 mais il n'hériterait d'aucun des autres droits root.

D'après ce que j'ai entendu, grsecurity est beaucoup plus simple à utiliser mais SELinux est plus sécurisé.

3
Aaron Digulla

Je pense que la meilleure solution est de sgid votre application et dès qu'elle a son port lié, elle devrait supprimer les privilèges en passant à un autre utilisateur.

2
Anxy Dicy

Une solution consiste à utiliser iptables pour exécuter PAT sur les paquets pour le port 80. Vous pouvez l'utiliser pour router les paquets vers le port local 8080, par exemple. Assurez-vous et ajustez les paquets sortants sur le port 80.

D'après mon expérience, les fonctionnalités d'autorisation fines de Linux ne sont pas compilées en noyaux standard en raison de problèmes de sécurité.

2
Darron

Si vous essayez de le faire pour qu'une commande exécutée par l'utilisateur puisse utiliser le port 80, alors vos seules solutions sont les astuces iptables ou la définition de l'exécutable setuid-to-root.

La façon dont quelque chose comme Apache fait cela (il se lie au port 80, mais s'exécute en tant que personne autre que root) consiste à s'exécuter en tant que root, se lier au port, puis changer la propriété du processus par l'utilisateur non privilégié après le port est installé. Si l'application que vous écrivez peut être exécutée par root, vous pouvez la faire changer de propriétaire en utilisateur non privé après la configuration des ports. Mais si c'est uniquement pour un utilisateur moyen de s'exécuter à partir de la ligne de commande, vous devrez utiliser l'une des autres solutions.

2
rjray

Lorsque j'ai diverses applications de service Web (scripts python, moteurs Tomcat, ...) que je ne veux pas exécuter en tant que root, je configure généralement un serveur Web Apache devant eux. Apache écoute le port 80 et Tomcat écoute 8080.

Dans Apache: s config:

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

Voir la documentation de mod-proxy pour plus d'informations: http://httpd.Apache.org/docs/2.2/mod/mod_proxy.html

2
Anders Westrup

Certains systèmes d'hôtes ne permettent pas d'utiliser le module NAT, 'iptables' ne résout pas le problème dans ce cas.

Que diriez-vous de xinetd?

Dans mon cas (Ubuntu 10.04)

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

Collez la configuration:

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

Alors:

# service xinetd restart

http://docs.codehaus.org/display/JETTY/port8 explique mieux.

1
Thomas

En passant, FreeBSD et Solaris (n'importe qui se souvient que un?) Vous permettent de le faire (se lier aux ports bas) sans escalade de privilèges (c'est-à-dire, en utilisant des programmes pour basculer vers root). Depuis que vous avez spécifié Linux, je poste simplement ceci comme un avis aux autres qui pourraient trouver cette question.

0
Daniel C. Sobral