ユーザランドプログラムがポート80と443にバインドできるようにカーネルパラメータを調整することは可能ですか?
私が尋ねる理由は、特権的なプロセスがソケットを開いて聞くことを許可することが愚かだと思うからです。ソケットを開いて待機するものはすべて危険度が高く、危険度の高いアプリケーションはrootとして実行しないでください。
Root権限で侵入したマルウェアを駆除するのではなく、特権のないプロセスがポート80を監視しているのかどうかを調べたいと思います。
私はここに他の答えやコメントが何を参照しているのかわからない。これはかなり簡単に可能です。 2つのオプションがあり、どちらもプロセスをrootに昇格させなくても番号の小さいポートにアクセスできます。
オプション1:少ない番号のポートにプロセスへのアクセスを許可するには、 CAP_NET_BIND_SERVICE
を使用します。
これにより、setcap
コマンドを使用して、特定のバイナリへの永続的なアクセスを許可して、小さい番号のポートにバインドできます。
Sudo setcap CAP_NET_BIND_SERVICE=+eip /path/to/binary
E/i/p部分の詳細については、 cap_from_text
を参照してください。
これを行った後、/path/to/binary
は小さい番号のポートにバインドすることができます。シンボリックリンクではなく、バイナリ自体にsetcap
を使用する必要があります。
オプション2:authbind
を使用してワンタイムアクセスを許可し、より細かいユーザー/グループ/ポート制御:
authbind
( マニュアルページ )ツールは、この目的のために存在します。
好きなパッケージマネージャを使ってauthbind
をインストールしてください。
関連するポートへのアクセスを許可するように設定してください。すべてのユーザーとグループから80と443を許可します。
Sudo touch /etc/authbind/byport/80
Sudo touch /etc/authbind/byport/443
Sudo chmod 777 /etc/authbind/byport/80
Sudo chmod 777 /etc/authbind/byport/443
authbind
を使用してコマンドを実行します(オプションで--deep
または他の引数を指定します。manページを参照)。
authbind --deep /path/to/binary command line args
例えば。
authbind --deep Java -jar SomeServer.jar
上記の両方には一長一短があります。オプション1はバイナリに信頼を与えますが、ポートごとのアクセスを制御することはできません。オプション2はユーザー/グループに信頼を与え、ポートごとのアクセスを制御しますが、残念ながらIPv4のみをサポートします。
デール・ハグルンドがスポットです。それで、私は同じことを異なる方法で、いくつかの詳細と例を挙げて言うつもりです。 ☺
UnixおよびLinuxの世界で正しいことは次のとおりです。
リスクが高い場所について間違った考えを持っています。高いリスクは、ネットワークから読み取り、読み取られたものに基づいて行動することです、ソケットを開いてポートにバインドするという単純な行為ではありません。 listen()
を呼び出します。リスクが高いのは、実際の通信を行うサービスの一部です。開く部分、bind()
、およびlisten()
、さらに(ある程度)accepts()
である部分は、高リスクではなく、スーパーユーザーのイージスの下で実行できます。ネットワーク上の信頼できない見知らぬ人の制御下にあるデータを(accept()
ケースのソースIPアドレスを除いて)使用および処理しません。
これを行うには多くの方法があります。
inetd
Dale Hagglundが言うように、古い「ネットワークスーパーサーバー」inetd
がこれを行います。サービスプロセスが実行されるアカウントは、inetd.conf
の列の1つです。リスニング部分とドロップする特権部分を、小さくて監査しやすい2つの別個のプログラムに分離しませんが、メインサービスコードを別個のプログラムに分離します。それは、それが生成するサービスプロセスのexec()
edソケットの開いているファイル記述子。
1つのプログラムを監査するだけでよいため、監査の難しさはそれほど問題ではありません。 inetd
の主な問題は、それほど多くの監査ではなく、最新のツールと比較して、単純なきめ細かいランタイムサービス制御を提供しないことです。
Daniel J. Bernsteinの CSPI-TCP および daemontools パッケージは、これを組み合わせて行うように設計されています。あるいは、Bruce Guenterのほぼ同等の daemontools-encore toolsetを使用できます。
ソケットファイル記述子を開き、特権ローカルポートにバインドするプログラムは、UCSPI-TCPから tcpserver
です。 listen()
とaccept()
の両方を実行します。
tcpserver
は、ルート特権自体をドロップするサービスプログラムを生成します(提供されるプロトコルは、スーパーユーザーとして起動し、たとえばFTPやSSHデーモンの場合のように「ログオン」する必要があるため)または- setuidgid
これは自己完結型の小さくて簡単に監査可能なプログラムであり、特権のみをドロップし、サービスプログラムにチェーンロードします(したがって、その一部は、たとえば、 qmail-smtpd
)。
したがって、サービスrun
スクリプトは、たとえば、次のようになります( dummyidentd の場合、これはヌルIDENTサービスを提供します)。
#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl
私のnoshパッケージ はこれを行うように設計されています。他と同じように、小さなsetuidgid
ユーティリティがあります。わずかな違いの1つは、systemd
スタイルの "LISTEN_FDS"サービスとUCSPI-TCPサービスで使用できることです。したがって、従来のtcpserver
プログラムは、tcp-socket-listen
とtcp-socket-accept
の2つの別個のプログラムに置き換えられます。
繰り返しますが、単一目的のユーティリティが相互に生成され、チェーンがロードされます。設計の興味深い特徴の1つは、listen()
の後、accept()
の前でもスーパーユーザー特権を削除できることです。以下は、qmail-smtpd
のrun
スクリプトです。
#!/bin/nosh
fdmove -c 2 1
clearenv --keep-path --keep-locale
envdir env/
softlimit -m 70000000
tcp-socket-listen --combine4and6 --backlog 2 ::0 smtp
setuidgid qmaild
sh -c 'exec \
tcp-socket-accept -v -l "${LOCAL:-0}" -c "${MAXSMTPD:-1}" \
ucspi-socket-rules-check \
qmail-smtpd \
'
スーパーユーザーのイージスの下で実行されるプログラムは、サービスに依存しない小さなチェーン読み込みツールfdmove
、clearenv
、envdir
、softlimit
、tcp-socket-listen
、およびsetuidgid
です。 sh
が開始されるまでに、ソケットは開かれてsmtp
ポートにバインドされ、プロセスにはスーパーユーザー特権がなくなります。
Laurent Bercotの s6 および s6-networking パッケージは、これを組み合わせて行うように設計されています。これらのコマンドは、daemontools
およびUCSPI-TCPのコマンドと構造的に非常に似ています。
run
スクリプトは、 s6-tcpserver
がtcpserver
に、 s6-setuidgid
がsetuidgid
に置き換えられることを除いて、ほぼ同じです。ただし、M。Bercotの execline ツールセットを同時に使用することもできます。
以下は、execline、s6、s6-networking、および publicfile のFTPサーバープログラムを使用する Wayne Marshallのオリジナル から少し変更したFTPサービスの例です。
#!/command/execlineb -PW
multisubstitute {
define CONLIMIT 41
define FTP_ARCHIVE "/var/public/ftp"
}
fdmove -c 2 1
s6-envuidgid pubftp
s6-softlimit -o25 -d250000
s6-tcpserver -vDRH -l0 -b50 -c ${CONLIMIT} -B '220 Features: a p .' 0 21
ftpd ${FTP_ARCHIVE}
Gerrit Papeの ipsvd は、ucspi-tcpおよびs6-networkingと同じ行に沿って実行される別のツールセットです。ツールは今回はchpst
とtcpsvd
ですが、同じことを行い、信頼できないクライアントによってネットワーク経由で送信されたものの読み取り、処理、書き込みを行う高リスクコードはまだ別のプログラムにあります。
#!/bin/sh
exec 2>&1
cd /public/10.0.5.4
exec \
chpst -m300000 -Uwwwuser \
tcpsvd -v 10.0.5.4 443 sslio -v -unobody -//etc/fnord/jail -C./cert.pem \
fnord
systemd
systemd
、一部のLinuxディストリビューションにある新しいサービス監視および初期化システム inetd
ができることを行うことを目的としています 。ただし、小さな自己完結型プログラムのスイートは使用しません。残念ながら、systemd
全体を監査する必要があります。
systemd
を使用すると、構成ファイルを作成して、systemd
がリッスンするソケットと、systemd
が開始するサービスを定義します。サービスの「ユニット」ファイルには、実行するユーザーなど、サービスプロセスを大幅に制御できる設定があります。
そのユーザーを非スーパーユーザーに設定すると、systemd
がソケットを開いてポートにバインドし、プロセス#でlisten()
(および必要に応じてaccept()
)を呼び出す作業をすべて行います。 1をスーパーユーザーとして実行すると、生成されるサービスプロセスはスーパーユーザー権限なしで実行されます。
私はかなり異なったアプローチをしています。 node.jsサーバーにポート80を使用したいと思いました。 Node.jsが非Sudoユーザー用にインストールされていたので、これを行うことができませんでした。シンボリックリンクを使おうとしましたが、うまくいきませんでした。
次に、あるポートから別のポートに接続を転送できることを知りました。そこで私はサーバをポート3000で起動し、ポート80からポート3000へのポート転送を設定しました。
このリンク はこれを行うために使用できる実際のコマンドを提供します。ここにコマンドがあります -
ローカルホスト/ループバック
Sudo iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 3000
外部の
Sudo iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 3000
私は2番目のコマンドを使用しました、そしてそれは私のために働きました。したがって、これはユーザープロセスが下位のポートに直接アクセスすることを許可せず、ポート転送を使用してアクセスできるようにするための中間的な理由と思います。
あなたの本能は完全に正しいです。複雑で大規模なプログラムをrootとして実行するのは悪い考えです。
ただし、通常のユーザーが特権付きポートにバインドできるようにすることも賢明ではありません。そのようなポートは通常重要なシステムサービスを表すからです。
この明らかな矛盾を解決するための標準的なアプローチは、特権の分離です。基本的な考え方は、プログラムを2つ(またはそれ以上)の部分に分割することです。それぞれの部分は、アプリケーション全体の明確に定義された部分を処理し、単純な限られたインタフェースによって通信します。
あなたが与える例では、あなたはあなたのプログラムを2つの部分に分けたいです。 rootとして実行され、特権付きソケットを開いてバインドし、それを別の部分(通常のユーザーとして実行されている部分)に渡します。
この分離を達成するためのこれら二つの主要な方法。
Rootとして起動する単一のプログラム。最初に行うことは、必要なソケットをできるだけ単純で制限された方法で作成することです。その後、特権を落とします。つまり、自分自身を通常のユーザーモードプロセスに変換し、その他すべての作業を行います。権限を正しく削除するのは難しいので、正しい方法を検討するために時間をかけてください。
親プロセスによって作成されたソケットペアを介して通信するプログラムのペア。非特権ドライバプログラムは初期引数を受け取り、おそらくいくつかの基本的な引数検証を行います。それはsocketpair()を介して接続されたソケットのペアを作成してから、実際の作業を行う2つの他のプログラムを分岐して実行し、ソケットペアを介して通信します。これらのうちの1つは特権があり、サーバーソケット、および他の特権がある操作を作成します、そしてもう1つはより複雑で、したがって信頼性の低いアプリケーションの実行を行います。