Eliminar Permisos De Root En Python


Me gustaría que un programa Python comenzara a escuchar en el puerto 80, pero después de eso se ejecutara sin permisos de root. ¿Hay alguna forma de eliminar root o de obtener el puerto 80 sin él?

Author: Sandeep Datta, 2010-04-23

6 answers

No podrá abrir un servidor en el puerto 80 sin privilegios de root, esto es una restricción a nivel del sistema operativo. Así que la única solución es eliminar los privilegios de root después de haber abierto el puerto.

Aquí hay una posible solución para eliminar privilegios de root en Python: Eliminar privilegios en Python. Esta es una buena solución en general, pero también tendrá que agregar os.setgroups([]) a la función para asegurarse de que la pertenencia al grupo del usuario root no se mantenga.

Copié y limpió un poco el código, y eliminó el registro y los controladores de excepciones para que dependa de usted manejar OSError correctamente (se lanzará cuando al proceso no se le permita cambiar su UID o GID efectivo):

import os, pwd, grp

def drop_privileges(uid_name='nobody', gid_name='nogroup'):
    if os.getuid() != 0:
        # We're not root so, like, whatever dude
        return

    # Get the uid/gid from the name
    running_uid = pwd.getpwnam(uid_name).pw_uid
    running_gid = grp.getgrnam(gid_name).gr_gid

    # Remove group privileges
    os.setgroups([])

    # Try setting the new uid/gid
    os.setgid(running_gid)
    os.setuid(running_uid)

    # Ensure a very conservative umask
    old_umask = os.umask(077)
 53
Author: Tamás,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-07 10:56:38

Recomiendo usar authbind para iniciar su programa Python, por lo que ninguno de ellos tiene que ejecutarse como root.

Https://en.wikipedia.org/wiki/Authbind

 12
Author: Allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-18 18:05:35

No es una buena idea pedirle al usuario que ingrese su nombre de usuario y grupo cada vez que necesite eliminar privilegios. Aquí hay una versión ligeramente modificada del código de Tamás que soltará privilegios y cambiará al usuario que inició el comando sudo. Asumo que estás usando sudo (si no, usa el código de Tamás).

#!/usr/bin/env python3

import os, pwd, grp

#Throws OSError exception (it will be thrown when the process is not allowed
#to switch its effective UID or GID):
def drop_privileges():
    if os.getuid() != 0:
        # We're not root so, like, whatever dude
        return

    # Get the uid/gid from the name
    user_name = os.getenv("SUDO_USER")
    pwnam = pwd.getpwnam(user_name)

    # Remove group privileges
    os.setgroups([])

    # Try setting the new uid/gid
    os.setgid(pwnam.pw_gid)
    os.setuid(pwnam.pw_uid)

    #Ensure a reasonable umask
    old_umask = os.umask(0o22)


#Test by running...
#./drop_privileges
#sudo ./drop_privileges
if __name__ == '__main__':
    print(os.getresuid())
    drop_privileges()
    print(os.getresuid())
 7
Author: Sandeep Datta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-08 10:06:17
  1. Systemd puede hacerlo por usted, si inicia su programa a través de systemd, systemd puede entregarle el zócalo de escucha ya abierto, y también puede activar su programa en la primera conexión. y ni siquiera necesitas demonizarlo.

  2. Si va a ir con el enfoque independiente, necesita la capacidad CAP_NET_BIND_SERVICE (comprobar la página de manual de capacidades). Esto se puede hacer programa por programa con la herramienta de línea de comandos correcta, o haciendo su aplicación (1) ser suid root (2) iniciar (3) escuchar el puerto (4) soltar privilegios / capacidades inmediatamente.

Recuerde que los programas raíz suid vienen con muchas consideraciones de seguridad (entorno limpio y seguro, umask, privilegios, rlimits, todas esas cosas son cosas que su programa va a tener que configurar correctamente). Si puedes usar algo como systemd, mucho mejor entonces.

 3
Author: Rudd-O,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-18 21:09:06

La mayor parte de esto funciona a menos que necesite solicitar el socket después de hacer otras cosas que no desea ser superusuario.

Hice un proyecto llamado tradesocket hace un tiempo. Le permite pasar sockets de ida y vuelta en un sistema posix entre procesos. Lo que hago es spin off un proceso al principio que permanece superusuario, y el resto del proceso cae en permisos y luego solicita el socket de la otra.

 2
Author: Brantley Harris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-19 04:20:56

Lo siguiente es una adaptación adicional de La respuesta de Tamás , con los siguientes cambios:

  • Utilice el python-prctl module para colocar las capacidades de Linux en una lista especificada de capacidades a preservar.
  • El usuario se puede pasar opcionalmente como un parámetro (por defecto busca el usuario que ejecutó sudo).
  • Establece todos los grupos de usuarios y HOME.
  • Opcionalmente cambia el directorio.

(Soy relativamente nuevo en el uso de este funcionalidad, sin embargo, por lo que puede haber perdido algo. Podría no funcionar en núcleos antiguos (

def drop_privileges(user=None, rundir=None, caps=None):
    import os
    import pwd

    if caps:
        import prctl

    if os.getuid() != 0:
        # We're not root
        raise PermissionError('Run with sudo or as root user')

    if user is None:
        user = os.getenv('SUDO_USER')
        if user is None:
            raise ValueError('Username not specified')
    if rundir is None:
        rundir = os.getcwd()

    # Get the uid/gid from the name
    pwnam = pwd.getpwnam(user)

    if caps:
        prctl.securebits.keep_caps=True
        prctl.securebits.no_setuid_fixup=True

    # Set user's group privileges
    os.setgroups(os.getgrouplist(pwnam.pw_name, pwnam.pw_gid))

    # Try setting the new uid/gid
    os.setgid(pwnam.pw_gid)
    os.setuid(pwnam.pw_uid)

    os.environ['HOME'] = pwnam.pw_dir

    os.chdir(os.path.expanduser(rundir))

    if caps:
        prctl.capbset.limit(*caps)
        try:
            prctl.cap_permitted.limit(*caps)
        except PermissionError:
            pass
        prctl.cap_effective.limit(*caps)

    #Ensure a reasonable umask
    old_umask = os.umask(0o22)

Se puede utilizar de la siguiente manera:

drop_privileges(user='www', rundir='~', caps=[prctl.CAP_NET_BIND_SERVICE])
 2
Author: Craig McQueen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-22 03:22:36