Je ne sais pas à quoi font référence les autres réponses et commentaires ici. C'est possible assez facilement. Il existe deux options, qui permettent toutes deux d'accéder aux ports à faible numéro sans avoir à élever le processus à root :
Option 1 :Utiliser CAP_NET_BIND_SERVICE
pour accorder un accès au port à faible numéro à un processus :
Avec cela, vous pouvez accorder un accès permanent à un binaire spécifique pour se lier aux ports à faible numéro via le setcap
commande :
sudo setcap CAP_NET_BIND_SERVICE=+eip /path/to/binary
Pour plus de détails sur la partie e/i/p, voir cap_from_text
.
Après avoir fait cela, /path/to/binary
sera en mesure de se lier aux ports à faible numéro. Notez que vous devez utiliser setcap
sur le binaire lui-même plutôt que sur un lien symbolique.
Option 2 :Utilisez authbind
pour accorder un accès unique, avec un contrôle utilisateur/groupe/port plus fin :
Le authbind
L'outil (page de manuel) existe précisément pour cela.
-
Installer
authbind
en utilisant votre gestionnaire de paquets préféré. -
Configurez-le pour accorder l'accès aux ports pertinents, par ex. pour autoriser 80 et 443 de tous les utilisateurs et groupes :
sudo touch /etc/authbind/byport/80 sudo touch /etc/authbind/byport/443 sudo chmod 777 /etc/authbind/byport/80 sudo chmod 777 /etc/authbind/byport/443
-
Exécutez maintenant votre commande via
authbind
(en spécifiant éventuellement--deep
ou d'autres arguments, voir la page de manuel):authbind --deep /path/to/binary command line args
Par exemple
authbind --deep java -jar SomeServer.jar
Il y a des avantages et des inconvénients dans les deux cas ci-dessus. L'option 1 accorde la confiance au binaire mais ne fournit aucun contrôle sur l'accès par port. L'option 2 accorde la confiance à l'utilisateur/groupe et fournit un contrôle sur l'accès par port, mais les anciennes versions ne prenaient en charge que IPv4 (depuis que j'ai écrit ceci à l'origine, des versions plus récentes prenant en charge IPv6 ont été publiées).
Dale Hagglund est sur place. Donc je vais juste dire la même chose mais d'une manière différente, avec quelques détails et exemples. ☺
La bonne chose à faire dans les mondes Unix et Linux est :
- avoir un petit programme simple, facilement vérifiable, qui s'exécute en tant que superutilisateur et lie le socket d'écoute ;
- pour avoir un autre petit programme simple, facilement vérifiable, qui supprime les privilèges générés par le premier programme ;
- avoir la viande du service, dans un tiers séparé programme, exécuté sous un compte non-superutilisateur et chargé en chaîne par le deuxième programme, s'attendant à hériter simplement d'un descripteur de fichier ouvert pour le socket.
Vous avez une mauvaise idée de l'endroit où se trouve le risque élevé. Le risque élevé est de lire à partir du réseau et d'agir sur ce qui est lu pas dans le simple fait d'ouvrir un socket, de le lier à un port et d'appeler listen()
. C'est la partie d'un service qui fait la communication réelle qui présente un risque élevé. Les parties qui s'ouvrent, bind()
, et listen()
, et même (dans une certaine mesure) la partie qui accepts()
, ne présentent pas de risque élevé et peuvent être exécutés sous l'égide du superutilisateur. Ils n'utilisent pas et n'agissent pas sur (à l'exception des adresses IP source dans le accept()
cas) des données qui sont sous le contrôle d'étrangers non fiables sur le réseau.
Il existe de nombreuses façons de procéder.
inetd
Comme le dit Dale Hagglund, l'ancien "superserveur réseau" inetd
est ce que ca. Le compte sous lequel le processus de service est exécuté est l'une des colonnes de inetd.conf
. Il ne sépare pas la partie écoute et la partie suppression des privilèges en deux programmes distincts, petits et facilement auditables, mais il sépare le code de service principal dans un programme séparé, exec()
ed dans un processus de service qu'il génère avec un descripteur de fichier ouvert pour le socket.
La difficulté de l'audit n'est pas vraiment un problème, car il suffit d'auditer un seul programme. inetd
Le problème majeur de n'est pas tant l'audit, mais plutôt le fait qu'il ne fournit pas un contrôle simple et précis du service d'exécution, par rapport aux outils plus récents.
UCSPI-TCP et daemontools
Les packages UCSPI-TCP et daemontools de Daniel J. Bernstein ont été conçus pour faire cela conjointement. On peut également utiliser l'ensemble d'outils daemontools-encore largement équivalent de Bruce Guenter.
Le programme pour ouvrir le descripteur de fichier socket et se lier au port local privilégié est tcpserver
, de l'UCSPI-TCP. Il fait à la fois le listen()
et le accept()
.
tcpserver
puis génère soit un programme de service qui supprime lui-même les privilèges root (car le protocole servi implique de commencer en tant que superutilisateur puis de "se connecter", comme c'est le cas avec, par exemple, un démon FTP ou SSH) ou setuidgid
qui est un petit programme autonome et facilement vérifiable qui supprime uniquement les privilèges, puis enchaîne les charges vers le programme de service proprement dit (dont aucune partie ne s'exécute donc jamais avec des privilèges de superutilisateur, comme c'est le cas avec, par exemple, qmail-smtpd
).
Un service run
script serait donc par exemple (celui-ci pour dummyidentd pour fournir un service null IDENT):
#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl
bouffe
Mon paquet nosh est conçu pour cela. Il a un petit setuidgid
utilitaire, comme les autres. Une légère différence est qu'il est utilisable avec systemd
-style "LISTEN_FDS" ainsi qu'avec les services UCSPI-TCP, donc le traditionnel tcpserver
programme est remplacé par deux programmes distincts :tcp-socket-listen
et tcp-socket-accept
.
Encore une fois, les utilitaires à usage unique apparaissent et se chargent en chaîne. Une particularité intéressante de la conception est que l'on peut supprimer les privilèges de superutilisateur après listen()
mais avant même accept()
. Voici un run
script pour qmail-smtpd
qui fait en effet exactement cela :
#!/bin/nosh
fdmove -c 2 1
clearenv --keep-path --keep-locale
envdir env/
softlimit -m 70000000
tcp-socket-listen --combine4and6 --backlog 2 ::0 smtp
setuidgid qmaild
sh -c 'exec \
tcp-socket-accept -v -l "${LOCAL:-0}" -c "${MAXSMTPD:-1}" \
ucspi-socket-rules-check \
qmail-smtpd \
'
Les programmes qui s'exécutent sous l'égide du superutilisateur sont les petits outils de chargement de chaîne indépendants des services fdmove
, clearenv
, envdir
, softlimit
, tcp-socket-listen
, et setuidgid
. Au point que sh
est démarré, le socket est ouvert et lié au smtp
port, et le processus n'a plus de privilèges de superutilisateur.
s6, mise en réseau s6 et execline
Les packages s6 et s6-networking de Laurent Bercot ont été conçus pour faire cela conjointement. Les commandes sont structurellement très similaires à celles de daemontools
et UCSPI-TCP.
run
les scripts seraient à peu près les mêmes, à l'exception de la substitution de s6-tcpserver
pour tcpserver
et s6-setuidgid
pour setuidgid
. Cependant, on peut également choisir d'utiliser en même temps l'ensemble d'outils execline de M. Bercot.
Voici un exemple de service FTP, légèrement modifié par rapport à l'original de Wayne Marshall, qui utilise execline, s6, s6-networking et le programme de serveur FTP de publicfile :
#!/command/execlineb -PW
multisubstitute {
define CONLIMIT 41
define FTP_ARCHIVE "/var/public/ftp"
}
fdmove -c 2 1
s6-envuidgid pubftp
s6-softlimit -o25 -d250000
s6-tcpserver -vDRH -l0 -b50 -c ${CONLIMIT} -B '220 Features: a p .' 0 21
ftpd ${FTP_ARCHIVE}
ipsvd
ipsvd de Gerrit Pape est un autre ensemble d'outils qui fonctionne dans le même sens que ucspi-tcp et s6-networking. Les outils sont chpst
et tcpsvd
cette fois, mais ils font la même chose, et le code à haut risque qui lit, traite et écrit les choses envoyées sur le réseau par des clients non fiables se trouve toujours dans un programme séparé.
Voici l'exemple de M. Pape d'exécution de fnord
dans un run
script :
#!/bin/sh
exec 2>&1
cd /public/10.0.5.4
exec \
chpst -m300000 -Uwwwuser \
tcpsvd -v 10.0.5.4 443 sslio -v -unobody -//etc/fnord/jail -C./cert.pem \
fnord
systemd
systemd
, le nouveau système de supervision et d'initialisation des services que l'on trouve dans certaines distributions Linux, est destiné à faire ce inetd
peut faire. Cependant, il n'utilise pas une suite de petits programmes autonomes. Il faut auditer systemd
dans son intégralité, malheureusement.
Avec systemd
on crée des fichiers de configuration pour définir un socket qui systemd
écoute, et un service qui systemd
départs. Le fichier "unité" de service a des paramètres qui permettent un grand contrôle sur le processus de service, y compris l'utilisateur sous lequel il s'exécute.
Avec cet utilisateur défini comme non superutilisateur, systemd
fait tout le travail d'ouverture du socket, de le lier à un port et d'appeler listen()
(et, si nécessaire, accept()
) dans le processus 1 en tant que superutilisateur, et le processus de service qu'il génère s'exécute sans privilèges de superutilisateur.
J'ai une approche assez différente. Je voulais utiliser le port 80 pour un serveur node.js. Je n'ai pas pu le faire car Node.js a été installé pour un utilisateur non sudo. J'ai essayé d'utiliser des liens symboliques, mais cela n'a pas fonctionné pour moi.
Ensuite, j'ai appris que je pouvais transférer les connexions d'un port à un autre. J'ai donc démarré le serveur sur le port 3000 et mis en place une redirection de port du port 80 vers le port 3000.
Ce lien fournit les commandes réelles qui peuvent être utilisées pour ce faire. Voici les commandes -
hôte local/bouclage
sudo iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 3000
externe
sudo iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 3000
J'ai utilisé la deuxième commande et cela a fonctionné pour moi. Je pense donc qu'il s'agit d'un terrain d'entente pour ne pas autoriser le processus utilisateur à accéder directement aux ports inférieurs, mais leur donner l'accès à l'aide de la redirection de port.