如果没有 root 权限,你将无法在端口 80 上打开服务器,这是操作系统级别的限制。因此,唯一的解决方案是在打开端口后降低权限。
以下是 Python 中降低权限的可能解决方案:Python 中的降低权限。这通常是一个不错的解决方案,但你还需要将 os.setgroups([])
添加到函数中,以确保不保留 root 用户的组成员身份。
我稍微修改了代码,并删除了日志记录和异常处理程序,因此你需要妥善处理 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)
/root
而不是/home/uid_name
,uid_name将无法对~/
执行任何操作,这将扩展为/root/
。这可能会影响像matplotlib这样在HOME目录中存储配置数据的模块。 authbind
似乎是处理此问题的正确方法。 - Daniel F我建议使用authbind
启动你的Python程序,这样就不必以root用户身份运行程序。
authbind
的示例 - http://goo.gl/fxFde6 - 将NodeJS替换为您喜欢的任何内容(例如:python) - starlocke/etc/authbind/byport/80
上的所有权/权限。 - mwfearnley我需要降低权限时,要求用户每次输入用户名和组不是个好主意。这里是Tamás代码稍作修改版,它将降低权限并切换到启动sudo命令的用户。我假设您正在使用sudo(如果没有,请使用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())
如果你通过systemd启动程序,systemd可以将已经打开的监听套接字移交给它,并且在第一次连接时激活你的程序,而且你甚至不需要将其作为守护进程。
如果你要选择独立的方法,你需要具备CAP_NET_BIND_SERVICE的能力(请查看capabilities man page)。这可以通过正确的命令行工具逐个程序完成,或者通过使你的应用程序(1)成为suid root (2)启动(3)监听端口(4)立即降低权限/能力来实现。
请记住,suid root程序有很多安全考虑因素(干净和安全的环境、umask、特权、资源限制等等都是你的程序必须正确设置的事情)。如果你可以使用类似systemd的东西,那就更好了。
python-prctl
模块将Linux权限降为指定的权限列表。sudo
的用户)。HOME
。(我相对于使用这个功能还比较新,可能会漏掉一些东西。它可能无法在旧内核(<3.8)或禁用文件系统权限的内核上工作。)
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])