Удаление корневых разрешений в Python - PullRequest
45 голосов
/ 23 апреля 2010

Я бы хотел, чтобы программа Python начала прослушивать порт 80, но после этого выполнялась без прав root.Есть ли способ удалить root или получить порт 80 без него?

Ответы [ 6 ]

56 голосов
/ 23 апреля 2010

Вы не сможете открыть сервер на порту 80 без привилегий root, это ограничение на уровне ОС.Поэтому единственное решение - удалить привилегии root после того, как вы открыли порт.

Вот возможное решение для удаления привилегий root в Python: Удаление привилегий в Python .В общем, это хорошее решение, но вам также необходимо добавить os.setgroups([]) в функцию, чтобы гарантировать, что членство в группе пользователя root не сохраняется.

Я скопировал и очистил код aнемного, и удалил журналирование и обработчики исключений, так что вам остается правильно обработать OSError (оно будет выброшено, когда процессу не разрешено переключать свой эффективный UID или GID):

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)
12 голосов
/ 18 ноября 2011

Я рекомендую использовать authbind для запуска вашей программы на Python, поэтому ни одна из них не должна запускаться от имени root.

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

7 голосов
/ 08 апреля 2014

Не рекомендуется просить пользователя вводить свое имя пользователя и группу всякий раз, когда мне нужно отказаться от привилегий. Вот слегка измененная версия кода Тамаса, которая отбросит привилегии и переключится на пользователя, который инициировал команду sudo. Я предполагаю, что вы используете sudo (если нет, используйте код Тамаса).

#!/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())
4 голосов
/ 19 ноября 2011
  1. systemd может сделать это за вас, если вы запустите свою программу через systemd, systemd может передать ей уже открытый прослушивающий сокет, а также может активировать вашу программу при первом подключении.и вам даже не нужно его демонизировать.

  2. Если вы собираетесь использовать автономный подход, вам нужна возможность CAP_NET_BIND_SERVICE (проверьте страницу руководства по возможностям).Это можно сделать для каждой программы с помощью правильного инструмента командной строки или сделать ваше приложение (1) suid root (2) запустить (3) прослушать порт (4) немедленно отбросить привилегии / возможности.

Помните, что корневые программы suid имеют множество соображений безопасности (чистая и безопасная среда, umask, привилегии, ограничения, все эти вещи должны быть установлены вашей программой).правильно).Если вы можете использовать что-то вроде systemd, тем лучше.

2 голосов
/ 22 июня 2017

Ниже приводится дальнейшая адаптация ответа Тамаса со следующими изменениями:

  • Используйте модуль python-prctl , чтобы отбросить возможности Linux вуказанный список возможностей для сохранения.
  • Пользователь может необязательно передаваться в качестве параметра (по умолчанию он ищет пользователя, который запустил sudo).
  • Устанавливает все группы пользователей.и HOME.
  • При желании он может изменить каталог.

(однако я относительно новичок в использовании этой функции, поэтому я мог что-то пропустить. Возможно, он не работаетстарые ядра (<3.8) или ядра с отключенными возможностями файловой системы.) </p>

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)

Может использоваться следующим образом:

drop_privileges(user='www', rundir='~', caps=[prctl.CAP_NET_BIND_SERVICE])
2 голосов
/ 19 ноября 2011

Большая часть этого работает, если вам не нужно запрашивать сокет после того, как вы делаете другие вещи, которые не хотите быть суперпользователем.

Я недавно создал проект под названием tradesocket . Это позволяет вам передавать туда и обратно сокеты в системе posix между процессами. В начале я делаю процесс, который остается суперпользователем, а остальная часть процесса падает в разрешениях, а затем запрашивает сокет у другого.

...