题 如何在Linux上以普通用户身份在端口80上运行服务器?


我已经搜索了很长一段时间,但找不到它。

我在Ubuntu Linux上并希望在端口80上运行服务器,但由于Ubuntu的安全机制,我收到以下错误:

java.net.BindException:权限被拒绝:80

我认为应该很简单,要么禁用这种安全机制,以便所有用户都可以使用端口80,或者为当前用户分配所需的权限以访问端口80。


281
2017-11-10 14:31




在另一个没有特权的端口上运行服务器有什么问题?您正在考虑像禁用安全机制那样严厉的事情,而不至少提供在该端口上运行服务器的非常严重的理由。服务器硬编码绑定到端口80吗?如果是这样,扔掉它。 - Anonymous
或Python错误消息: socket.error: [Errno 13] Permission denied - Kazark
可能重复 普通用户使用1024以下的端口 - Roman
你不能。低于1024的端口是特权的,只有root可以打开它们的侦听套接字。适当的做法是在打开权限后删除权限。 - Falcon Momot
“匿名” - 世界各地的用户都经过培训,可以在某些港口寻找某些服务。在某些情况下,它已经标准化。例如,端口80上的HTTP和端口443上的HTTPS。它很难改变世界的用户和标准。 - jww


答案:


简答:你不能。低于1024的端口只能由root打开。根据评论 - 嗯,你可以,使用 CAP_NET_BIND_SERVICE但是,应用于java bin的那种方法将使得任何java程序都可以使用此设置运行,如果不是安全风险,这是不可取的。

答案很长:您可以将端口80上的连接重定向到您可以作为普通用户打开的其他端口。

以root身份运行:

# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

由于环回设备(如localhost)不使用预先路由规则,如果需要使用localhost等,也要添加此规则(谢谢@Francesco):

# iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

注意:以上解决方案 不是 非常适合多用户系统,因为任何用户都可以打开端口8080(或您决定使用的任何其他高端口),从而拦截流量。 (致记者 CesarB)。

编辑:根据评论问题 - 删除上述规则:

# iptables -t nat --line-numbers -n -L

这将输出如下内容:

Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:8080 redir ports 8088
2    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 redir ports 8080

你感兴趣的规则是nr。 2,所以删除它:

# iptables -t nat -D PREROUTING 2

330
2017-11-10 14:41



@Sunny:upvotes不是西方最快的枪,而是最好的回应。你到目前为止是最好的(我只提到了iptables;你实际上提供了完整的命令行)。我唯一拥有你的不是关于其他用户也可以绑定到端口8080的警告。 - CesarB
请注意,这不适用于IPv6。 - Emmanuel Bourg
有人可以解释我以后如何删除这条规则吗?运行之后,它可以工作,但它显然不是一个“规则”,因为当我这样做时它不会出现 sudo iptables --list。我知道iptables是什么和做什么,但在此之前我从未真正使用它。 - Encoderer
感谢您的回答...每当我重新启动Ubuntu时,此规则都会消失,我必须再次运行它。有没有办法永远保存它? - Coderji
@Coderji:检查社区文档中的“保存”部分: help.ubuntu.com/community/IptablesHowTo - Sunny


使用 authbind

如果启用Java的仅IPv4堆栈,它甚至可以与Java一起使用。我用:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …

77
2017-11-14 13:12



如果服务器是Tomcat,您可以通过设置自动使用authbind AUTHBIND=yes 在/ etc / default / tomcat6中 - Emmanuel Bourg
我无法使用默认的Java包在Ubuntu服务器上运行... - Ashley Steel
我也不知道任何解决方案? - mark
请注意,您必须配置 authbind 实际上允许这种情况发生。从手册页: “/ etc / authbind / byport / port已经过测试。如果可以根据访问权限(2)访问该文件给主叫用户,则授权绑定到该端口。”,例如对于80号港口, sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80。初次安装 authbind 通常没有任何预先配置的授权。 - Jason C
哦nonononononono,永远不要chmod 777什么! - Johannes


如果您的系统支持它,您可以使用功能。查看man功能,您需要的功能是CAP_NET_BIND_SERVICE。

在较新的Debian / Ubuntu上,您可以运行:

sudo apt-get install libcap2-bin 
sudo setcap 'cap_net_bind_service=+ep' /path/to/program

45
2018-05-30 20:32



这适用于nodejs:setcap'cap_net_bind_service = + ep'/ usr / bin / nodejs - JasonS
这个。我想知道为什么这个答案没有更多的赞成。比iptables选项imho容易得多。 - Dominik R
这是正确且最有效的答案,所有其他答案都会导致性能下降或只是不确定/不安全。 - OneOfOne


另一个解决方案是使您的应用程序setuid,以便它可以与端口80绑定。作为root,执行以下操作

chown root ./myapp
chmod +S ./myapp

请记住,除非完全正确,否则这样做会使您面临潜在的安全漏洞,因为您的应用将与网络通信,并将以完全root权限运行。如果你采用这个解决方案,你应该查看Apache或Lighttpd的源代码或类似的东西,他们使用root权限打开端口,但是然后立即放弃那些priv并“成为”一个较低特权的用户,这样劫机者无法接管整台电脑。

更新:如图所示 这个问题从2.6.24开始,Linux内核似乎有一个新的功能,允许你将可执行文件(当然不是脚本)标记为具有“CAP_NET_BIND_SERVICE“功能。如果你安装了debian软件包”libcap2-bin“,你可以通过发出命令来实现

setcap 'cap_net_bind_service=+ep' /path/to/program

39
2017-11-10 14:44



这与以root身份运行相同,除非应用知道如何删除权限。 - CesarB
这很危险。这意味着任何请求都将以root身份运行。这是因为即使apache以root身份开始绑定,然后将权限下放给另一个用户。 - Sunny
Paul:iptables并不是那么危险,因为即使应用程序遭到破坏,它也不会在攻击时暴露系统,至少不会使用root权限。以root身份运行应用程序是另一回事。 - Sunny
iptables的危险只有当这是一个多用户系统时,正如CesarB所说,因为任何人都可以绑定到8080,并拦截流量。 - Sunny
大声笑,爱接受的答案如何有-15 - Evan Teran


Sunny和CesarB提出的方法:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

工作正常,但它有一个小缺点 - 它不会阻止用户直接连接到端口8080而不是80。

当这可能是一个问题时,请考虑以下情况。

假设我们有一台服务器接受端口8080上的HTTP连接和端口8181上的HTTPS连接。

我们使用iptables建立以下重定向:

80  ---> 8080
443 ---> 8181

现在,让我们假设我们的服务器决定将用户从HTTP页面重定向到HTTPS页面。除非我们仔细地重写响应,否则它将重定向到 https://host:8181/。在这一点上,我们被搞砸了:

  • 一些用户会将这个标记为 https://host:8181/ 网址,我们需要维护此网址,以避免破坏他们的书签。
  • 其他用户将无法连接,因为他们的代理服务器不支持非标准SSL端口。

我使用以下方法:

iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp --dport 443 -j MARK --set-mark 1
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8181
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -m mark --mark 1 -j ACCEPT
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8181 -m mark --mark 1 -j ACCEPT

结合INPUT链上的默认REJECT规则,此方法可防止用户直接连接到端口8080,8181


35
2018-02-20 16:19



这很好,但为什么不将守护进程绑定到localhost:8080而不是0.0.0.0:8080?我想这样做,但我需要iptables。 - Amala
它很有用,非常酷。 - xtian


我只是在前面使用Nginx。它也可以在localhost上运行。

  • apt-get install nginx

.. 要么 ..

  • pkg_add -r nginx 

..或什么适合您的操作系统。

如果在localhost上运行,nginx.conf中所需的只是:

服务器{
        听80;
        server_name some.domain.org;
        地点 / {
            proxy_set_header Host $ host;
            proxy_set_header X-Real-IP $ remote_addr;
            proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:8081;
        }
}

34
2017-11-20 14:30



我非常喜欢这个解决方案。 - thomasfedb
这是JFrog自己建议的解决方案之一: jfrog.com/confluence/display/RTF/nginx - stolsvik


传统上在Unix上,只有root可以绑定到低端口(<1024)。

解决此问题的最简单方法是在服务器上运行  端口(例如,8080)并使用简单的iptables规则将连接从端口80转发到端口8080.请注意,这样会丢失对低端口的额外保护;您计算机上的任何用户都可以绑定到端口8080。


29
2017-11-10 14:36





如果您的系统支持它,您可以使用功能。看到 man capabilities,你需要的那个 CAP_NET_BIND_SERVICE。不,我自己从未使用过它们,我不知道它们是否真的有效:-)


23
2017-11-10 16:27



他们确实工作,我使用CAP_NET_RAW像普通用户一样运行tcpdump等工具。 - Justin