Linuxで通常のユーザーとしてポート80でサーバーを実行する方法は?


311

私はかなり長い間解決策についてGoogleで調べましたが、答えが見つかりませんでした。

Ubuntu Linuxでポート80でサーバーを実行したいのですが、Ubuntuのセキュリティメカニズムにより、次のエラーが表示されます。

java.net.BindException:許可が拒否されました:80

すべてのユーザーがポート80を使用できるようにこのセキュリティメカニズムを無効にするか、現在のユーザーにポート80にアクセスするために必要な特権を割り当てるのは、十分に簡単だと思います。


3
特権のない別のポートでサーバーを実行する問題は何ですか?そのポートでサーバーを実行するための少なくとも非常に重大な理由を提供せずに、セキュリティメカニズムを無効にすることと同じくらい過酷なことを考えています。サーバーはポート80にバインドするようにハードコードされていますか?もしそうなら、それを捨てます。
匿名


4
できません。1024未満のポートには特権があり、rootのみがそれらのリスニングソケットを開くことができます。適切なことは、それを開いた後に許可をドロップすることです。
ファルコンモモット

2
「匿名」-世界中のユーザーは、特定のポートで特定のサービスを探すように訓練されています。場合によっては、標準化されています。たとえば、ポート80のHTTPとポート443のHTTPS。この種のユーザーと世界の標準を変更するのは難しい。

1
@FalconMomot 1024未満のポートに特権がある場合、Apacheサーバーがポート80でルート特権を取得するためにパスワードを入力する必要がないのはなぜですか?質問者は、そのように物事を行う方法を知りたいと思います(技術的にはルートとして使用されているかどうか)。Deepak Mittal、私が間違っているかどうかお気軽に教えてください。
シュル

回答:


355

簡単な答え:できません。1024未満のポートは、rootのみが開くことができます。コメントによると-よく、CAP_NET_BIND_SERVICEを使用してできますが、そのアプローチをjava binに適用すると、javaプログラムがこの設定で実行されます。

長い答え:ポート80の接続を、通常のユーザーとして開くことができる他のポートにリダイレクトできます。

ルートとして実行:

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

ループバックデバイス(localhostなど)は事前ルーティングルールを使用しないため、localhostなどを使用する必要がある場合は、このルールも追加してください(thanks @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:賛成票は西で最速の銃ではなく、最高の反応です。これまでのところ最高のものです(iptablesについてのみ言及しましたが、実際には完全なコマンドラインを提供しました)。地雷があなたを持っている唯一のものは、他のユーザーに関する注意事項は、ポート8080に結合することができるではありません
CesarB

3
これはIPv6では機能しないことに注意してください。
エマニュエルブール

3
後でこのルールを削除する方法を誰かが説明できますか?実行した後は動作しますが、実行すると表示されないため、明らかに「ルール」ではありませんsudo iptables --list。私はiptablesが何であり、何をするか知っていますが、これまで実際に使ったことはありません。
エンコーダー

4
答えてくれてありがとう... Ubuntuを再起動すると、このルールは消えてしまい、もう一度実行する必要があります。永久に保存する方法はありますか?
Coderji 14

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に設定することで自動的にauthbindを使用できます
Emmanuel Bourg

デフォルトのJavaパッケージを使用してUbuntuサーバーでこれを動作させることができませんでした...
アシュリー

私も、既知の解決策はありますか?
マーク

10
authbindこれを実際に許可するように設定する必要があることに注意してください。manページから:「/ etc / authbind / byport / portがテストされています。access(2)に従って、このファイルが呼び出しユーザーに実行のためにアクセス可能である場合、ポートへのバインドが許可されます。」、ポート80用などsudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80。の初期インストールにauthbindは、通常、事前に構成された承認はありません。
ジェイソンC

4
ノノノノノノノ
ヨハネス

57

システムでサポートされている場合は、機能を使用できます。man機能を参照してください。必要なものはCAP_NET_BIND_SERVICEです。

新しいDebian / Ubuntuでは、次を実行できます。

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よりもはるかに簡単です。
ドミニクR

5
これは、最も効率的な正解であり、他のすべての解答は、パフォーマンスヒットを引き起こすか、単に不確か/安全ではありません。
OneOfOne

41

別の解決策は、ポート80でバインドできるようにアプリをsetuidすることです。rootとして、以下を実行します

chown root ./myapp
chmod +S ./myapp

アプリがネットワークと通信し、完全なルート権限で実行されるため、これを行うと、絶対に正しく行われない限り、潜在的なセキュリティホールにさらされることに注意してください。この解決策を講じる場合は、ApacheやLighttpdなどのソースコードを見てください。ルート権限を使用してポートを開きますが、すぐにそれらの権限を放棄し、より低い権限のユーザーに「なる」ようにします。ハイジャッカーがコンピュータ全体を乗っ取ることはできません。

更新:この質問に見られるように、2.6.24以降のLinuxカーネルには、実行可能ファイル(もちろんスクリプトではない)に「CAP_NET_BIND_SERVICE」機能があるというマークを付けることができる新しい機能があるようです。debianパッケージ「libcap2-bin」をインストールする場合は、次のコマンドを発行してそれを行うことができます

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

6
アプリが権限を削除する方法を知らない限り、これはルートとして実行するのと同じです。
CesarB 08年

14
これは危険です。これは、リクエストがルートとして実行されることを意味します。これは、Apacheでもバインドするルートとして起動し、その後、別のユーザーに特権をドロップするためです。
サニー

9
ポール:iptablesはそれほど危険ではありません。アプリが危険にさらされたとしても、少なくともルート権限がなければ、攻撃に対してシステムを公開しないからです。ルートとしてアプリを実行することもまた別の話です。
サニー

1
誰でも8080にバインドしてトラフィックを傍受できるため、CesarBが言ったように、iptablesの危険性は、これがマルチユーザーシステムである場合のみです。
晴れ

1
笑、受け入れられた答えが-15を持っている方法が大好き
エヴァンテラン

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 $ 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自体から提案された解決策の1つです。jfrog.com
confluence

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

INPUTチェーンのデフォルトのREJECTルールと組み合わせることで、このアプローチにより、ユーザーがポート8080、8181に直接接続できないようになります。


1
これは良いことですが、なぜデーモンを0.0.0.0:8080ではなくlocalhost:8080にバインドしないのですか?それをやりたいのですが、そのためにはiptablesが必要です。
アマラ

うまくいき、本当にクールです。
xtian

29

伝統的にUnixでは、ルートのみが低いポート(<1024)にバインドできます。

これを回避する最も簡単な方法は、高いポート(8080など)でサーバーを実行し、単純なiptablesルールを使用して接続をポート80からポート8080に転送することです。これにより、追加の保護が失われます。ローポート; マシン上のすべてのユーザーがポート8080にバインドできます。


23

システムでサポートされている場合は、機能を使用できます。参照してくださいman capabilities、あなたが必要なものになるでしょうCAP_NET_BIND_SERVICE。いいえ、私は自分でそれらを使用したことがないので、本当に機能するかどうかはわかりません


1
それらは機能します。CAP_NET_RAWを使用して、通常のユーザーとしてtcpdumpなどのツールを実行します。
ジャスティン

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
これには同じ問題があります。ルートとしてサービスを実行するのは悪い習慣です。
ケビンパンコ

4

サニーの答えは正しいですが、ループバックインターフェイスはPREROUTINGテーブルを使用しないため、追加の問題に直面する可能性があります。

追加するiptablesルールは2つです。

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では、次の2つのオプションがあります。

Linuxカーネルの両方の拡張機能により、非常に細かいレベルでアクセス権を付与できます。これにより、このプロセスにポート80を開くことを許可できますが、他のルート権限は継承されません。

私が聞いたところでは、grsecurityの使用ははるかに簡単ですが、SELinuxはより安全です。


2

1つの解決策は、iptablesを使用してポート80のパケットでPATを実行することです。これを使用して、たとえばパケットをローカルポート8080にルーティングできます。必ず発信パケットをポート80に戻して調整してください。

私の経験では、セキュリティの問題のために、Linuxのきめ細かい許可機能は標準カーネルにコンパイルされません。


2

ユーザー実行コマンドがポート80を使用できるようにこれを実行しようとしている場合、唯一の解決策はiptablesトリックまたは実行可能setuid-to-rootの設定です。

Apacheのようなものがこれを行う方法(ポート80にバインドしますが、ルート以外のユーザーとして実行します)は、ルートとして実行し、ポートにバインドし、ポートの後にプロセスの所有権を非特権ユーザーに変更します設定されています。あなたが書いているアプリができる場合に実行するルートで、あなたは、ポートが設定された後、それは非PRIVのユーザーに所有者を変更することができます。ただし、これが平均的なユーザーがコマンドラインから実行するだけの場合は、他のソリューションのいずれかを使用する必要があります。


2

ルートとして実行したくないさまざまなWebサービスアプリケーション(Pythonスクリプト、Tomcatエンジンなど)がある場合、通常はそれらの前にApache Webサーバーを構成します。Apacheはポート80をリッスンし、tomcatは8080をリッスンします。

apache:s config:

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が失われることです。
エマニュエルブール

2

最善の解決策はアプリをsgidすることで、ポートがバインドされるとすぐに別のユーザーに切り替えて特権を削除する必要があると思います。


1

一部のホストシステムはNATモジュールの使用を許可していません。この場合、「iptables」は問題を解決しません。

xinetdはどうですか?

私の場合(ubuntu 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などの専用ソリューションと比較すると、かなり非効率的です。
エマニュエルブール

-1

余談ですが、FreeBSDとSolaris(だれでも覚えていますか?)を使用すると、特権を昇格させることなく(つまり、ルートに切り替えるプログラムを使用して)これを(低ポートにバインドして)実行できます。Linuxを指定したので、この質問を見つける可能性のある他の人への通知としてこれを投稿しています。


-1

ネクロマンシング。

シンプル。通常または古いカーネルでは、そうではありません。
他の人が指摘したように、iptablesはポートを転送できます。
他の人からも指摘されているように、CAP_NET_BIND_SERVICEも仕事をすることができます。
もちろん、スクリプトからプログラムを起動した場合、CAP_NET_BIND_SERVICEは失敗します。シェルインタープリターにキャップを設定しない限り、意味がありません。サービスをルートとして実行することもできます。
たとえば、Javaの場合、適用する必要があります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です。

すでにすべてです。
カーネルをコンパイルし、インストールします。
リブート。
完了-その愚かな制限はGONEであり、スクリプトでも機能します。

カーネルのコンパイル方法は次のとおりです。

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を使用し、この制限が二度とわからないことを確認したい場合はカーネルをコンパイルします。


誰かが下票について説明してくれませんか?カーネルコンパイルが機能しませんか?それとも、その後、通常のリポジトリからカーネルアップグレードを行うことができなくなったからですか?
苦境

私はこの解決策を試しました(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 directory、javaに上限が設定されている場合は常に取得します。unix.stackexchange.com/a/16670/55508
ダニエルアルダー

1
追加<javahome>/lib/amd64/jli/ld.so.confて実行することで以前のエラーを解決しましたsudo ldconfig
ダニエルアルダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.