参考文献

参考文献

私は C で HTTP サーバー デーモンを作成しており (理由があります)、それを systemd ユニット ファイルで管理しています。

私は 20 年前、1995 年頃に設計されたアプリケーションを書き直しています。そこで使用されているシステムは、chroot してから setuid するという標準的な手順です。

以前の仕事では、いかなるプロセスも決して root として実行しないというポリシーが一般的でした。そのためのユーザー/グループを作成し、そこから実行していました。もちろん、システムは一部の処理を root として実行していましたが、すべてのビジネス ロジック処理は root にならずに実行できました。

HTTP デーモンについては、アプリケーション内で chroot しない限り、root なしで実行できます。では、アプリケーションを root として実行しない方が安全ではないでしょうか?

最初から mydaemon-user として実行する方が安全ではないでしょうか? root で起動し、chroot してから、mydaemon-user に setuid するよりも安全ではないでしょうか?

答え1

他の人はあなたのポイントを見逃しているようです。それは、変更されたルートを使用する理由ではなく、もちろんあなたはすでにそれを知っているし、デーモンに制限をかけるために他に何ができるかでもありません。権限のないユーザーアカウントの保護下で実行することも明らかに知っています。しかし、なぜこのようなことをするのか。アプリケーション内実際に、その理由を示す非常に的確な例があります。

Daniel J. Bernstein の publicfile パッケージのデーモン プログラムの設計について考えてみましょうhttpd。最初に行うことは、コマンド引数で使用するように指示されたルート ディレクトリにルートを変更し、次に 2 つの環境変数で渡された権限のないユーザー ID とグループ ID に権限を付与することです。

デーモン管理ツールセットには、ルートディレクトリの変更や権限のないユーザーやグループIDへのドロップなどの専用ツールがあります。Gerrit Papeのrunitにはchpst私のnoshツールセットにはchrootそしてsetuidgid-fromenvローラン・ベルコのs6はs6-chrootそしてs6-setuidgidウェイン・マーシャルの犯罪者はruntoolそしてrunuidなどなど。実際、それらはすべてM. Bernsteinの独自のdaemontoolsツールセットを備えており、setuidgid先行詞として。

httpdこうした専用ツールから機能を抽出して使用できると考える人もいるでしょう。そして、あなたが想像しているように、いいえサーバー プログラムの一部がスーパーユーザー権限で実行されることはありません。

問題は、直接的な結果として、変更されたルートを設定するために大幅に多くの作業を行う必要があり、これにより新たな問題が発生することです。

バーンスタインhttpdの現状では、のみルートディレクトリツリーにあるファイルとディレクトリは、世界に公開されるものです。他には何もない木にはまったくありません。さらに、どれでも実行可能プログラム イメージ ファイルがそのツリー内に存在します。

しかし、ルート ディレクトリの変更をチェーン ローディング プログラム (または systemd) に移動すると、突然、のプログラム イメージ ファイル、ロードされる共有ライブラリ、およびプログラム初期化中にプログラム ローダーまたは C ランタイム ライブラリがアクセスする、、、およびhttpd内の特殊ファイル(C または C++ プログラムの場合、これは非常に驚くかもしれません) が削除されます。/etc/run/devtrussstraceまた変更されたルートに存在する必要があります。そうでない場合はhttpdチェーンできず、ロード/実行されません。

これはHTTP(S)コンテンツサーバーであることを忘れないでください。変更されたルートにあるあらゆる(誰でも読める)ファイルを提供する可能性があります。これには、共有ライブラリ、プログラムローダー、オペレーティングシステムのさまざまなローダー/CRTL構成ファイルのコピーなどが含まれます。そして、何らかの(偶然の)手段でコンテンツサーバーが次のファイルにアクセスした場合、書くこうしたことが行われた場合、侵害を受けたサーバーは、自分自身のプログラム イメージ、またはシステムのプログラム ローダーへの書き込みアクセス権を取得する可能性があります。(現在、、、、およびディレクトリのhttpd2 つの並列セットを安全に維持する必要があることに注意してください。)/usr/lib/etc/run/dev

httpdただし、ルートを変更して権限自体を削除する場合はこの限りではありません。

つまり、監査が比較的容易で、プログラムの起動時にhttpdスーパーユーザー権限で実行される少量の特権コードを使用することと引き換えに、変更されたルート内のファイルとディレクトリの攻撃対象領域が大幅に拡大されることになります。

このため、すべてをサービス プログラムの外部で実行するほど簡単ではありません。

ただし、これはあくまでも最低限の機能に過ぎないことに注意してくださいhttpd。オペレーティングシステムのアカウントデータベースでユーザーIDとグループIDを検索し、環境変数に設定するなどの処理を実行するすべてのコードは、プログラムの外部でhttpd、次のような単純なスタンドアロンの監査可能なコマンドで実行されますenvuidgid。(もちろんこれはUCSPIツールなので、関連するTCPポートをリッスンしたり、接続を受け入れたりするコードは含まれていません。これらは次のようなコマンドの領域です。tcpservertcp-socket-listentcp-socket-accepts6-tcpserver4-socketbinders6-tcpserver4d、 等々。)

参考文献

答え2

あなたの質問の詳細の多くは、私が最近調べた にも同様に当てはまると思いますavahi-daemon。(ただし、異なる別の詳細を見逃している可能性があります)。avahi-daemon が侵害された場合、chroot で avahi-daemon を実行すると多くの利点があります。これには次のものが含まれます。

  1. ユーザーのホームディレクトリを読み取って個人情報を盗み出すことはできません。
  2. /tmp に書き込むことで他のプログラムのバグを悪用することはできません。そのようなバグには少なくとも 1 つのカテゴリがあります。例:https://www.google.co.uk/search?q=tmp+race+security+bug
  3. 他のデーモンがメッセージをリッスンして読み取っている可能性のある、chroot 外の Unix ソケット ファイルを開くことはできません。

ポイント3は、特に次のような場合に便利です。ないdbus または類似のものを使用します... avahi-daemon は dbus を使用するので、chroot 内からでもシステム dbus へのアクセスが確保されると思います。システム dbus でメッセージを送信する機能が必要ない場合は、その機能を拒否すると、非常に優れたセキュリティ機能になる可能性があります。

systemdユニットファイルで管理する

avahi-daemon が書き直された場合、セキュリティのために systemd に依存し、たとえば を使用する可能性があることに注意してくださいProtectHome。私は、chroot では保証されない追加の保護とともに、これらの保護を追加レイヤーとして追加するように avahi-daemon に変更することを提案しました。私が提案したオプションの完全なリストは、こちらで確認できます。

https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a をご覧ください。

avahi-daemonがそうしていたら、もっと制限があったかもしれないようですないchroot 自体を使用します。その一部はコミット メッセージに記載されています。ただし、これがどの程度適用されるかはわかりません。

注意: 私が使用した保護では、デーモンが UNIX ソケット ファイルを開くことを制限していませんでした (上記のポイント 3)。

もう 1 つのアプローチは、SELinux を使用することです。ただし、アプリケーションを Linux ディストリビューションのサブセットに結び付けることになります。ここで SELinux を肯定的に考えた理由は、SELinux がプロセスの dbus へのアクセスをきめ細かく制限するからです。たとえば、systemdメッセージを送信する必要があるバス名のリストに含まれていないことがよくあると思います :-)。

「systemd サンドボックスを使用する方が chroot/setuid/umask/... よりも安全かどうか疑問に思っていました。」

要約: 両方ではどうでしょうか? 上記を少し解読してみましょう :-)。

ポイント 3 について考えると、chroot を使用すると、より制限が厳しくなります。ProtectHome= およびその仲間は、chroot ほど制限を厳しくしようとさえしません。(たとえば、systemd の named オプションのどれも/run、unix ソケット ファイルを配置する傾向があるブラックリストには入りません)。

chrootはファイルシステムへのアクセスを制限することが非常に強力であることを示していますが、すべてLinux では、これはファイルです :-)。ファイル以外のものを制限できる systemd オプションがあります。これは、プログラムが侵害された場合に役立ち、プログラムが利用できるカーネル機能を減らして、脆弱性を悪用しようとする可能性があります。たとえば、avahi-daemon には Bluetooth ソケットは必要ありませんし、Web サーバーも必要ないでしょう :-)。したがって、AF_BLUETOOTH アドレス ファミリへのアクセスを許可しないでください。オプションを使用して、AF_INET、AF_INET6、およびおそらく AF_UNIX をホワイトリストに追加してくださいRestrictAddressFamilies=

使用する各オプションのドキュメントをお読みください。一部のオプションは他のオプションと組み合わせるとより効果的ですが、一部のオプションはすべての CPU アーキテクチャで使用できるわけではありません。(CPU が悪いのではなく、その CPU の Linux ポートが適切に設計されていないためだと思います)。

(ここには一般的な原則があります。拒否したいものではなく、許可したいもののリストを記述できると、より安全になります。たとえば、chroot を定義すると、アクセスが許可されているファイルのリストが提供され、これはブロックしたいと言うよりも堅牢です/home)。

原則として、setuid() の前に同じ制限をすべて自分で適用できます。これはすべて、systemd からコピーできるコードにすぎません。ただし、systemd ユニット オプションは記述がはるかに簡単になり、標準形式になっているため、読みやすく、確認も容易になります。

したがって、ターゲットプラットフォームのサンドボックスセクションを一読することを強くお勧めしますman systemd.exec。ただし、可能な限り安全な設計が必要な場合は、プログラムで試してみることを躊躇しないでくださいchroot(その後、root権限を削除します)。同じように. ここではトレードオフがあります。 を使用すると、chroot全体的な設計にいくつかの制約が課せられます。 chroot を使用する設計が既にあり、必要なことを実行しているように見える場合は、それは非常に素晴らしいことです。

答え3

systemd に頼れるのであれば、サンドボックス化を systemd に任せた方が確かに安全 (かつ簡単!) です。 (もちろん、アプリケーションは systemd によってサンドボックス化されて起動されたかどうかを検出し、まだルートである場合はそれ自体をサンドボックス化することもできます。) あなたが説明したサービスに相当するものは次のようになります。

[Service]
ExecStart=/usr/local/bin/mydaemon
User=mydaemon-user
RootDirectory=...

しかし、それだけではありません。systemd は他にも多くのサンドボックス化を実行できます。以下に例をいくつか示します。

[Service]
# allocate separate /tmp and /var/tmp for the service
PrivateTmp=yes
# mount / (except for some subdirectories) read-only
ProtectSystem=strict
# empty /home, /root
ProtectHome=yes
# disable setuid and other privilege escalation mechanisms
NoNewPrivileges=yes
# separate network namespace with only loopback device
PrivateNetwork=yes
# only unix domain sockets (no inet, inet6, netlink, …)
RestrictAddressFamilies=AF_UNIX

man 5 systemd.execより多くのディレクティブとより詳細な説明については、 を参照してください。デーモンをソケットアクティブ化可能にすると ( man 5 systemd.socket)、ネットワーク関連のオプションも使用できます。サービスの外部へのリンクは systemd から受信したネットワークソケットのみになり、他のものに接続できなくなります。一部のポートのみを listen し、他のサーバーに接続する必要がない単純なサーバーの場合は、これが役立ちます。(ファイル システム関連のオプションによって がRootDirectory時代遅れになる可能性もあると思います。そのため、必要なバイナリとライブラリをすべて含む新しいルート ディレクトリを設定する手間はもうかからないでしょう。)

新しいバージョンの systemd (v232 以降) は もサポートしておりDynamicUser=yes、systemd はサービスの実行時にのみサービス ユーザーを自動的に割り当てます。つまり、サービスに永続的なユーザーを登録する必要がなく、サービスが 、 、 以外のファイル システムの場所に書き込まない限り、正常に動作しますStateDirectory(LogsDirectoryこれらCacheDirectoryはユニット ファイルで宣言することもできます。 をもう一度参照してください。man 5 systemd.execまた、systemd はこれを管理し、動的ユーザーに正しく割り当てるように注意します)。

関連情報