Linux에서 일반 사용자로 포트 80에서 서버를 실행하는 방법은 무엇입니까?


311

한동안 해결책에 대해 Google에 답변했지만 답변을 찾지 못했습니다.

Ubuntu Linux를 사용하고 있고 포트 80에서 서버를 실행하려고하지만 Ubuntu의 보안 메커니즘으로 인해 다음 오류가 발생합니다.

java.net.BindException : 권한 거부 : 80

모든 사용자가 포트 80을 사용할 수 있도록이 보안 메커니즘을 비활성화하거나 포트 80에 액세스하기 위해 현재 사용자에게 필요한 권한을 할당하는 것이 간단해야한다고 생각합니다.


3
권한이없는 다른 포트에서 서버를 실행하는 데 어떤 문제가 있습니까? 최소한 해당 포트에서 서버를 실행해야하는 매우 심각한 이유를 제공하지 않으면 서 보안 메커니즘을 비활성화하는 것만 큼 어려운 문제에 대해 생각하고 있습니다. 서버가 포트 80에 바인딩하도록 하드 코드되어 있습니까? 그렇다면 버리십시오.
익명


4
당신은 할 수 없습니다. 1024 미만의 포트는 권한이 있으며 루트 만이 청취 소켓을 열 수 있습니다. 적절한 방법은 사용 권한을 연 후 삭제하는 것입니다.
Falcon Momot

2
"익명"-전 세계 사용자가 특정 포트에서 특정 서비스를 찾도록 훈련되었습니다. 경우에 따라 표준화되었습니다. 예를 들어 포트 80의 HTTP와 포트 443의 HTTPS가 있습니다. 사용자와 세계 표준을 변경하기는 어렵습니다.

1
@FalconMomot 1024 미만의 포트가 권한이있는 경우 Apache 서버가 포트 80에서 루트 권한을 얻기 위해 비밀번호를 입력하지 않아도되는 이유는 무엇입니까? 질문자는 기술적으로 루트로 사용되는지 여부에 관계없이 그렇게하는 방법을 알고 싶다고 생각합니다. 내가 틀렸다면 알려주세요, Deepak Mittal.
Shule

답변:


355

짧은 대답 : 당신은 할 수 없습니다. 1024 미만의 포트는 루트로만 열 수 있습니다. 주석에 따라 -CAP_NET_BIND_SERVICE 사용할 수 있지만 Java bin에 적용된 접근 방식은이 설정으로 모든 Java 프로그램을 실행하므로 보안 위험이 아니라면 바람직하지 않습니다.

긴 대답 : 포트 80의 연결을 일반 사용자로 열 수있는 다른 포트로 리디렉션 할 수 있습니다.

루트로 실행하십시오.

# 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

13
@Sunny : upvotes는 서쪽에서 가장 빠른 총을위한 것이 아니라 최고의 응답을위한 것입니다. 당신은 지금까지 최고입니다 (나는 iptables 만 언급했습니다. 실제로 전체 명령 줄을 제공했습니다). 다른 사용자들도 포트 8080에 바인딩 할 수 있다는 경고가 있습니다.
CesarB

3
IPv6에서는 작동하지 않습니다.
Emmanuel Bourg

3
나중에 원하는 경우이 규칙을 제거하는 방법을 설명 할 수 있습니까? 그것을 실행 한 후에는 작동하지만 분명히 할 때 표시되지 않기 때문에 분명히 "규칙"이 아닙니다 sudo iptables --list. 나는 iptables가 무엇인지 그리고 무엇인지 알고 있지만, 전에는 실제로 그것을 사용하지 않았습니다.
Encoderer

4
답변 주셔서 감사합니다 ... Ubuntu를 재부팅 할 때 마다이 규칙이 사라지고 다시 실행해야합니다. 영원히 저장하는 방법이 있습니까?
Coderji

4
@Coderji : 커뮤니티 설명서에서 "저장"섹션을 확인하십시오. help.ubuntu.com/community/IptablesHowTo
Sunny

79

authbind를 사용하십시오 .

Java의 IPv4 전용 스택을 활성화하면 Java 와도 작동합니다. 나는 사용한다:

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

4
서버가 Tomcat 인 경우 AUTHBIND=yes/ etc / default / tomcat6
Emmanuel Bourg

기본 Java 패키지가있는 Ubuntu 서버에서이 작업을 수행 할 수 없었습니다 ...
Ashley

나도 알려진 해결책이 있습니까?
마크

10
authbind실제로 이러한 상황이 발생하도록 구성해야합니다 . man 페이지에서 : "/ etc / authbind / byport / port가 테스트되었습니다. access (2)에 따라 호출하는 사용자가이 파일에 액세스 할 수 있으면 포트에 대한 바인딩이 승인됩니다." 예를 들어 포트 80의 경우 sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80. 초기 설치 authbind에는 일반적으로 사전 구성된 권한이 없습니다.
Jason C

4
오 nonononononono, 절대 777을 chmod하지 마십시오!
Johannes

57

시스템에서 지원하는 경우 기능을 사용할 수 있습니다. CAP_NET_BIND_SERVICE가 필요한 기능을 참조하십시오.

최신 데비안 / 우분투에서는 다음을 실행할 수 있습니다.

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

이것은 nodejs에서 작동합니다. setcap 'cap_net_bind_service = + ep'/ usr / bin / nodejs
JasonS

5
이. 이 답변이 더 이상지지되지 않는 이유가 궁금합니다. iptables 옵션 imho보다 훨씬 쉽습니다.
Dominik R

5
이것은 정확하고 가장 효율적인 답변입니다. 다른 모든 답변은 성능 저하를 일으키거나 불안정하거나 안전하지 않습니다.
OneOfOne 2016 년

41

또 다른 해결책은 포트 80과 바인딩 할 수 있도록 앱 setuid를 만드는 것입니다. 루트로 다음을 수행하십시오.

chown root ./myapp
chmod +S ./myapp

앱이 네트워크와 통신하고 전체 루트 권한으로 실행되므로 절대적으로 올바르게 수행하지 않으면이 작업을 수행하면 잠재적 인 보안 허점에 노출 될 수 있습니다. 이 솔루션을 사용하는 경우 루트 권한을 사용하여 포트를 여는 Apache 또는 Lighttpd 또는 이와 유사한 소스 코드를 확인한 다음 즉시 해당 권한을 포기하고 권한이 낮은 사용자가 "되"도록해야합니다. 하이재커는 전체 컴퓨터를 인수 할 수 없습니다.

업데이트 : 이 질문 에서 볼 수 있듯이 2.6.24 이후의 Linux 커널에는 실행 가능 (스크립트는 아님)을 " CAP_NET_BIND_SERVICE"기능 이있는 것으로 표시 할 수있는 새로운 기능이 있습니다. 데비안 패키지 "libcap2-bin"을 설치하면, 다음 명령을 실행하면됩니다 :

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

6
앱이 권한을 삭제하는 방법을 모르는 경우 루트로 실행하는 것과 같습니다.
CesarB

14
이것은 위험합니다. 이는 모든 요청이 루트로 실행됨을 의미합니다. 아파치조차도 루트로 시작하여 바인딩 한 다음 다른 사용자에게 권한을 삭제하기 때문입니다.
Sunny

9
Paul : iptables는 그렇게 위험하지 않습니다. 앱이 손상 되더라도 루트 권한이 아닌 공격에 시스템이 노출되지 않기 때문입니다. 루트로 앱을 실행하는 것은 또 다른 이야기입니다.
Sunny

1
iptables의 위험은 CesarB가 말한 것처럼 누구나 8080에 바인딩하여 트래픽을 가로 챌 수있는 것처럼 다중 사용자 시스템 인 경우에만 가능합니다.
Sunny

1
lol, 받아 들여진 대답이 -15 인 방법을 좋아합니다
Evan Teran

40

나는 단순히 Nginx를 앞에 사용합니다. localhost에서도 실행할 수 있습니다.

  • apt-get install nginx

.. 또는 ..

  • pkg_add -r nginx

.. 또는 OS에 적합한 것.

localhost에서 실행중인 경우 nginx.conf에 필요한 것은 다음과 같습니다.

서버 {
        듣고 80;
        server_name some.domain.org;
        위치 / {
            proxy_set_header 호스트 $ 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;
        }
}

나는이 솔루션을 정말 좋아한다.
thomasfedb

1
:이 (중 하나) JFrog 자체에서 제안 된 솔루션입니다 jfrog.com/confluence/display/RTF/nginx
stolsvik

36

Sunny와 CesarB가 제안한 접근법 :

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

잘 작동하지만 작은 단점이 있습니다. 사용자가 80 대신 8080 포트에 직접 연결하는 것을 방해하지 않습니다.

이것이 문제가 될 수있는 경우 다음 시나리오를 고려하십시오.

포트 8080에서 HTTP 연결을 허용하고 포트 8181에서 HTTPS 연결을 허용하는 서버가 있다고 가정합니다.

iptables를 사용하여 다음 리디렉션을 설정합니다.

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

이제 서버가 사용자를 HTTP 페이지에서 HTTPS 페이지로 리디렉션하기로 결정했다고 가정 해 봅시다. 응답을 신중하게 다시 작성하지 않으면로 리디렉션됩니다 https://host:8181/. 이 시점에서 우리는 망했다.

  • 일부 사용자는 https://host:8181/URL을 북마크에 추가하고 북마크가 손상되지 않도록이 URL을 유지해야합니다.
  • 프록시 서버는 비표준 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

이 접근 방식은 입력 체인의 기본 거부 규칙과 결합하여 사용자가 포트 8080, 8181에 직접 연결할 수 없도록합니다.


1
이것은 좋지만 0.0.0.0:8080 대신 localhost : 8080에 데몬을 바인딩하는 이유는 무엇입니까? 나는 그것을하고 싶지만 그것을 위해 iptables가 필요합니다.
Amala

정말 멋지다.
xtian

29

일반적으로 Unix에서는 루트 만 낮은 포트 (<1024)에 바인딩 할 수 있습니다.

이 문제를 해결하는 가장 간단한 방법은 높은 포트 (예 : 8080) 에서 서버를 실행 하고 간단한 iptables 규칙을 사용하여 포트 80에서 포트 8080으로 연결을 전달하는 것입니다. 낮은 포트; 컴퓨터의 모든 사용자는 포트 8080에 바인딩 할 수 있습니다.


23

시스템에서 지원하는 경우 기능을 사용할 수 있습니다. man capabilities당신이 필요로하는 것은 참조하십시오 CAP_NET_BIND_SERVICE. 아니요, 나는 그들을 직접 사용하지 않았으며 실제로 작동하는지 모르겠습니다 :-)


1
그들은 CAP_NET_RAW를 사용하여 일반 사용자로 tcpdump와 같은 도구를 실행합니다.
Justin

12

애플리케이션 서버 앞에서 리버스 프록시 (nginx, apache + mod_proxy) 또는 캐싱 리버스 프록시 (Squid, Varnish)를 사용하십시오!

리버스 프록시를 사용하면 다음과 같은 많은 흥미로운 것을 얻을 수 있습니다.

  • 로드 밸런싱
  • 사용자가 멋진 오류 페이지를 수신하여 애플리케이션 서버 다시 시작
  • 캐시로 작업 속도 향상
  • 애플리케이션 서버가 아닌 리버스 프록시로 일반적으로 수행하는 세분화 된 설정

6

redir 프로그램을 사용할 수 있습니다 :

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1

4

sudo를 사용하십시오.

일반 사용자가 적절한 명령을 실행할 수 있도록 sudo를 구성하십시오.

/etc/init.d/httpd start

또는

apachectl stop

또는

/usr/local/apache2/apachectl restart

또는

/myapp/myappbin start

(또는 특정 웹 서버 / 앱을 시작 / 중지하기 위해 사용하는 다른 명령 / 스크립트)


8
루트와 같은 서비스를 실행하는 것은 나쁜 습관입니다.
Kevin Panko

4

sunny의 대답은 정확하지만 루프백 인터페이스가 PREROUTING 테이블을 사용하지 않으므로 추가 문제가 발생할 수 있습니다.

추가 할 iptables 규칙은 두 가지입니다.

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

3

Linux에는 다른 두 가지 옵션이 있습니다.

Linux 커널에 대한 두 가지 확장을 통해 매우 세밀한 수준에서 액세스 권한을 부여 할 수 있습니다. 이렇게하면이 프로세스에 포트 80을 열 수 있지만 다른 루트 권한은 상속되지 않습니다.

내가 들었던 것으로부터 grsecurity는 사용하기가 훨씬 간단하지만 SELinux는 더 안전합니다.


2

한 가지 해결책은 iptables를 사용하여 포트 80의 패킷에서 PAT를 수행하는 것입니다. 예를 들어,이를 사용하여 패킷을 로컬 포트 ​​8080으로 라우팅 할 수 있습니다. 나가는 패킷을 다시 포트 80으로 조정하십시오.

필자의 경험에 따르면 Linux의 세분화 된 권한 기능은 보안 문제로 인해 표준 커널로 컴파일되지 않습니다.


2

사용자 실행 명령이 포트 80을 사용할 수 있도록이 작업을 수행하려는 경우 유일한 해결책은 iptables 트릭이나 실행 가능한 setuid-to-root 설정입니다.

Apache와 같은 방법으로 포트 80에 바인딩하지만 루트가 아닌 다른 사람으로 실행되는 방법은 루트로 실행하고 포트에 바인딩 한 다음 포트 후 권한이없는 사용자에게 프로세스 소유권을 변경하는 것입니다. 설정되었습니다. 작성중인 앱을 루트 로 실행할 수있는 경우 포트를 설정 한 후 소유자를 비 개인 사용자로 변경할 수 있습니다. 그러나 이것이 일반 사용자가 명령 줄에서 실행하는 것이라면 다른 솔루션 중 하나를 사용해야합니다.


2

루트로 실행하고 싶지 않은 다양한 웹 제공 응용 프로그램 (python 스크립트, tomcat 엔진 등)이 있으면 일반적으로 그 앞에 Apache 웹 서버를 구성합니다. Apache는 포트 80을 청취하고 tomcat은 8080을 청취합니다.

아파치 : s 구성에서 :

ProxyPass /webapp http://localhost:8080/webapp
ProxyPassReverse /webapp http://localhost:8080/webapp

자세한 내용은 mod-proxy 설명서를 참조하십시오. http://httpd.apache.org/docs/2.2/mod/mod_proxy.html


1
이 솔루션의 단점은 Tomcat 로그에서 들어오는 IP가 손실된다는 것입니다.
Emmanuel Bourg

2

가장 좋은 해결책은 앱을 sgid하는 것이며 포트가 바인딩되면 다른 사용자로 전환하여 권한을 삭제해야합니다.


1

일부 호스트 시스템은 NAT 모듈을 사용할 수 없으므로 'iptables'는이 경우 문제를 해결하지 못합니다.

xinetd는 어떻습니까?

내 경우에는 (우분투 10.04)

# apt-get install xinetd
# touch /etc/xinetd.d/my_redirect
# vim /etc/xinetd.d/my_redirect

구성을 붙여 넣습니다.

service my_redirector_80
{
 disable = no
 socket_type = stream
 protocol = tcp
 user = root
 wait = no
 port = 80
 redirect = localhost 8080
 type = UNLISTED
}

그때:

# service xinetd restart

http://docs.codehaus.org/display/JETTY/port80에서 더 잘 설명합니다.


1
이는 기본적으로 서버 앞에 리버스 프록시를 배치하는 것과 동일하지만 HTTP 프로토콜을 이해하고 X-Forwarded-For와 같은 유용한 헤더를 추가 할 수있는 HAproxy, Pound 또는 Varnish와 같은 전용 솔루션에 비해 다소 비효율적입니다.
Emmanuel Bourg

-1

여담으로, FreeBSD의 및 Solaris는 (사람이 기억 하나?) 당신은 권한 상승없이이 (낮은 포트에 바인드) (즉, 프로그램을 사용하여 루트로 전환하기 위해) 할 수 있습니다. Linux를 지정 했으므로이 질문을 찾을 수있는 다른 사람들에게 통지로 게시하고 있습니다.


-1

괴롭힘.

단순한. 정상적인 커널이나 오래된 커널로는 그렇지 않습니다.
다른 사람들이 지적했듯이 iptables는 포트를 전달할 수 있습니다.
다른 사람들이 지적한 것처럼 CAP_NET_BIND_SERVICE도 작업을 수행 할 수 있습니다.
물론 CAP_NET_BIND_SERVICE는 스크립트에서 프로그램을 시작하면 실패합니다. 쉘 인터프리터에 제한을 설정하지 않으면 서비스를 루트로 실행할 수 있습니다.
예를 들어 Java의 경우이를 적용해야합니다. 자바 JVM으로

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java

분명히 이것은 모든 Java 프로그램이 시스템 포트를 바인딩 할 수 있음을 의미합니다.
모노 /.NET 용 Dito

또한 xinetd가 최고의 아이디어는 아니라고 확신합니다.
그러나 두 방법 모두 해킹이므로 제한을 해제하여 한계를 높이 지 않는 이유는 무엇입니까?
아무도 당신이 정상적인 커널을 실행해야한다고 말하지 않았으므로, 당신은 당신 자신을 실행할 수 있습니다.

최신 커널 (또는 현재 가지고있는 커널)의 소스를 다운로드하기 만하면됩니다. 이후에 다음으로 이동합니다.

/usr/src/linux-<version_number>/include/net/sock.h:

이 라인을 찾으십시오

/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK       1024

로 변경

#define PROT_SOCK 0

안전하지 않은 ssh 상황을 원하지 않으면 다음과 같이 변경하십시오. #define PROT_SOCK 24

일반적으로 필요한 가장 낮은 설정 (예 : http의 경우 79, 포트 25에서 SMTP를 사용할 때는 24)을 사용합니다.

그게 다야
커널을 컴파일하고 설치하십시오.
재부팅하십시오.
완료-바보 같은 한계는 사라졌고 스크립트에서도 작동합니다.

커널을 컴파일하는 방법은 다음과 같습니다.

https://help.ubuntu.com/community/Kernel/Compile

# You can get the kernel-source via package linux-source, no manual download required
apt-get install linux-source fakeroot

mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>

# Apply the changes to PROT_SOCK define in /include/net/sock.h

# Copy the kernel config file you are currently using
cp -vi /boot/config-`uname -r` .config

# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev

# Run menuconfig (optional)
make menuconfig

# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers

# And wait a long long time

cd ..

간단히 말해서, 보안을 유지하려면 iptables를 사용하고,이 제한이 다시는 귀찮게하지 않도록하려면 커널을 컴파일하십시오.


누군가 downvotes를 설명해 주시겠습니까? 커널 컴파일이 작동하지 않습니까? 아니면 나중에 일반 리포지토리에서 커널 업그레이드를 더 이상 수행 할 수 없기 때문입니까?
Quandary September

이 솔루션 ( sudo setcap cap_net_bind_service=+ep /path-to-java/java)을 시도했지만 java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directoryJava에 캡이 설정되어 있으면 항상 얻습니다 . unix.stackexchange.com/a/16670/55508
Daniel Alder

1
추가하여 이전 오류를 해결 <javahome>/lib/amd64/jli/ld.so.conf하고 실행sudo ldconfig
다니엘 알더
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.