我已经用 C 编写了自己的 Web 服务器。如何在不成为 root 用户的情况下将其绑定到端口 80,从而不影响安全性(缓冲区溢出等)?
我应该简单地转发来自在端口 80 上运行的另一台“稳定”服务器的任何流量吗?
使用转发代理确实是最简单和最推荐的解决方案。它还具有在非常无效的请求到达您自己编写的服务器之前过滤它们的优点。
如果您的应用程序将用户的 IP 地址用于某些事情,请记住从您的网络服务器使用的任何标头中检索它(X-Client-IP
等等)。但是,只对真正来自您的网络服务器的请求这样做,否则用户可能会欺骗他们的 IP。您可以通过检查请求是否来自您的 IP 并在这种情况下仅检查标头来执行此操作,或者只是让您的应用程序绑定到 localhost。
另一种解决方案是授予程序该CAP_NET_BIND_SERVICE
功能。这需要 root 才能使用setcap cap_net_bind_service=ep /path/to/the/executable
- 由于该标志存储在文件系统属性中,因此在将文件复制到另一个系统或重新编译应用程序时它将丢失。
当然你也可以让你的程序 setuid root 然后在调用bind()
. 但是,根据您的程序如何工作以及它的作用,这可能不是一个好主意 - 例如,如果它出于某种原因需要关闭并重新打开侦听套接字,则需要完全重新启动该进程。
以 root身份调用然后放弃特权的另一种方法bind()
是让 root 进程创建套接字并绑定它,然后使用SCM_RIGHTS
消息通过 UNIX 域套接字连接将侦听套接字传递给非特权进程。
如果要将服务器绑定到端口 80,则必须以 root 身份执行此操作,然后删除权限。
bind(sockfd, addr, addrlen);
/* process is running as root, drop privileges after bind*/
if (setgid(groupid) != 0)
errx(1, "setgid: Unable to drop group privileges: %s", strerror(errno));
if (setuid(userid) != 0)
errx(1, "setuid: Unable to drop user privileges: %S", strerror(errno));
如何在没有 root 身份的情况下将其绑定到端口 80,以免安全性受到损害(缓冲区溢出等)
不以 root 身份运行不会使您的系统更安全,它只是增加了另一个可利用的层。因此,与其考虑如何不以 root 身份运行,请确保您不使用任何已知不安全的函数,如strcpy()
,sprintf()
等,而是使用strncpy()
,snprintf()
等。
众所周知,Unix 中 1024 以下的所有端口都需要 root 权限才能打开。在 Unix 系统上,您不希望以 root 权限运行的应用程序越少越好。这是并且将永远是一个很大的安全风险。
另一种方法是使用 iptables 将端口 80 的流量重定向到更无害的端口,如 8080。这里是关于如何设置它的描述。
iptables 不是最容易设置的工具,但是一旦你掌握了它,它就会非常有用和强大(而且安全)。
我在这个问题上工作了很长一段时间,得出的结论是systemd
+iptables
是解决方案,而不是Capabilities,正如这里详细阐述的那样。