私は(理由のために)CでHTTPサーバーデーモンを作成し、それを管理するためにsystemdユニットファイルを使用しています。
私は20年前の1995年頃に設計されたアプリケーションを書き直しています。彼らが使用するシステムは最初にchroot、それからsetuidと標準的な手順です。
以前の職場では、どのプロセスもルートとして実行しないのが一般的なポリシーでした。これに対してユーザー/グループを作成し、そこで実行します。もちろん、システムはいくつかのタスクをルートとして実行しますが、ルートなしですべてのビジネスロジック処理を実装できます。
HTTPデーモンの場合、アプリケーション内でchrootを実行しない限り、ルートなしで実行できます。もしそうなら、アプリケーションが絶対ルートとして実行されないのは安全ではないでしょうか?
最初からmydaemon-userで実行する方が安全ではないでしょうか? rootで起動してchrootingしてからmydaemon-userでsetuidを起動する代わりに?
答え1
他の人があなたのポイントを理解していないようです。もちろん、すでに明確にわかっている変更されたルートを使用したいのではなく、デーモンを制限するために何ができるのかもしれません。デーモンプロセスは、権限のないユーザーアカウントの助けを借りて実行されますが、なぜこれを行うのですか?アプリケーション内部。実際、その理由についてはかなり良い例があります。
httpd
Daniel J. Bernsteinのpublicfileパッケージにあるデーモンのデザインを検討してください。最初に行うことは、ルートをコマンド引数で使用するようにルートディレクトリに変更してから、2つの環境変数に渡された権限のないユーザーIDとグループIDに権限を付与することです。
デーモン管理ツールセットには、ルートディレクトリの変更、権限のないユーザー、およびグループIDの削除などのタスク用の特別なツールがあります。 Gerrit Papeのrunitは次のとおりです。chpst
。私のnoshツールセットにchroot
そしてsetuidgid-fromenv
。ローランベルコのs6はs6-chroot
そしてs6-setuidgid
。ウェインマーシャルのPerpはruntool
そしてrunuid
。など。実際、彼らはすべてM. Bernsteinの独自のdaemontoolsツールセットを持っています。setuidgid
先行して。
httpd
これらの専門ツールから機能を抽出して使用できると考えることもできます。それでは皆さんが想像するように、いいえスーパーユーザー権限で実行するために使用されるサーバープログラムの一部です。
問題は、即時の結果に変更されたルートを設定するためにさらに多くの作業を行う必要があり、これが新しい問題を公開することです。
バーンスタインによるとhttpd
、ただルートツリーのファイルとディレクトリは、世界に公開されるファイルとディレクトリです。持つ他の人はいません。文字通り木にあります。さらに、理由もありません。どの実行可能なプログラムイメージファイルがこのツリーに存在します。
ただし、ルートディレクトリをチェーンローダ(またはsystemd)に変更すると、突然プログラムイメージファイル、ロードされる共有ライブラリ、プログラムhttpd
の初期化中にプログラムローダまたはCランタイムライブラリからアクセスする特別なファイルが表示されます(CまたはC ++でプログラムする場合)。、あなたはとても驚くかもしれません)、/etc
/run
/dev
truss
strace
返品変更のルートに存在する必要があります。それ以外の場合はhttpd
リンクされず、ロード/実行されません。
これはHTTP(S)コンテンツサーバーであることを覚えておいてください。変更されたルートディレクトリにあるすべての(誰でも読みやすい)ファイルを提供できます。これには、共有ライブラリ、プログラムローダ、およびオペレーティングシステムのさまざまなローダ/CRTL設定ファイルのコピーが含まれます。何らかの手段で(偶然に)コンテンツサーバーがアクセスできるという意味である場合書くしたがって、感染したサーバーは、httpd
独自のプログラムイメージまたはシステムのプログラムローダへの書き込みアクセス権を取得することもできます。 (今、安全のために/usr
、、/lib
およびディレクトリ/etc
の2つの並列セットがあることを忘れないでください。)/run
/dev
httpd
これらのどれも、ルートを変更して権限自体を削除するわけではありません。
したがって、監査が容易で、httpd
プログラムの起動時にスーパーユーザー権限で実行される少量の特権コードは、すでに変更されているルートディレクトリのファイルとディレクトリに対する攻撃面を大幅に拡張します。
そのため、サービスプログラムの外ですべてを行うのと同じくらい簡単ではありません。
これはそれ自体がまだ最小限の機能であることに注意してくださいhttpd
。オペレーティングシステムのアカウントデータベースでユーザーIDとグループIDを検索し、その環境変数を最初に入力するなどの操作を実行するすべてのコードはいプログラムの外部では、単純httpd
なスタンドアロンの監査可能なコマンドenvuidgid
(UCSPI ツールなので、関連する TCP ポートをリッスンしたり、コマンド ドメインに属する接続を受け入れるコードは含まれません)。tcpserver
、tcp-socket-listen
、tcp-socket-accept
、s6-tcpserver4-socketbinder
、s6-tcpserver4d
、等。 )
追加読書
- バーンスタイン、ダニエル(1996)。
httpd
。公開文書。 cr.yp.to. httpd
。ソフトウェア統合(Daniel J. Bernstein)。ソフトウェア。ジョナサン・デ・ボーインポラード。 2016.gopherd
。ソフトウェア統合(Daniel J. Bernstein)。ソフトウェア。ジョナサン・デ・ボーインポラード。 2017.- https://unix.stackexchange.com/a/353698/5132
- https://github.com/janmojzis/httpfile/blob/master/droproot.c
答え2
avahi-daemon
あなたの質問に関する多くの詳細は、私が最近見たものにも同様に当てはまると思います。 (他の詳細を見逃している可能性があります。)chrootでavahi-daemonを実行すると、avahi-daemonが破損した場合に多くの利点があります。これには以下が含まれます。
- ユーザーのホームディレクトリを読み取ることができず、個人情報を盗むことはできません。
- /tmpに記録して他のプログラムのバグを利用することはできません。そのようなエラーには少なくともクラス全体があります。例えばhttps://www.google.co.uk/search?q=tmp+race+security+bug
- chrootの外では、Unixソケットファイルを開くことができず、他のデーモンがファイルからのメッセージを聞いて読み取ることができます。
時いいえdbusなどを使用してください。 avahi-daemon は dbus を使用するので、chroot 内でもシステム dbus へのアクセスを保証します。システムの dbus からメッセージを送信する機能が不要な場合、その機能を拒否することは非常に良いセキュリティ機能になります。
システム単位ファイルを使用した管理
ProtectHome
avahi-daemonをオーバーライドする場合は、セキュリティのためにsystemdに依存することを選択できます。いいですね。 。ここで私が思いついたオプションの完全なリストを見ることができます。
https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a
avahi-daemonがこれを行うと、より多くの制限が利用できるようです。いいえchroot自体を使用してください。そのうちのいくつかはコミットメッセージに記載されています。これがどの程度まで適用されるのかよくわかりません。
私が使用している保護機能は、デーモンがUnixソケットファイルを開くことを制限しません(上記の3項目)。
もう一つの方法はSELinuxを使用することです。ただし、アプリケーションをLinuxディストリビューションのサブセットに関連付けることはできます。ここでSELinuxを肯定的に見る理由は、SELinuxがdbusへのプロセスのアクセスを細かい方法で制限するからです。たとえば、通常、systemd
メッセージを送信できる必要があるバス名のリストにこの名前がないとします。 :-).
「systemd sandboxの使用がchroot/setuid/umask/...より安全であるかどうかを知りたいです」
要約:なぜ両方にすることはできませんか?上記の内容を少し解釈してみましょう。 :-).
ポイント3を考慮すると、chrootを使用するとより多くの制限が提供されます。 ProtectHome =と友達はchrootのように制限しようとしません。 (たとえば、systemdオプションのブラックリストを指定しないと、/run
通常はUnixソケットファイルをブラックリストに追加します)。
chrootは、ファイルシステムへのアクセスを制限することが非常に強力である可能性があることを示していますが、そうではありません。すべてLinuxではファイルです:-).ファイル以外のコンテンツを制限するためのいくつかのシステムオプションがあります。これはプログラムが破損している場合に便利で、脆弱性を悪用しようとする可能性のあるカーネル機能を減らす可能性があります。たとえば、avahi-daemonはBluetoothソケットを必要とせず、あなたのWebサーバーにも必要ないようです:-).したがって、AF_BLUETOOTHアドレスファミリへのアクセスを許可しないでください。 AF_INET、AF_INET6、またはAF_UNIXをホワイトリストに追加するには、このオプションを使用しますRestrictAddressFamilies=
。
使用する各オプションのマニュアルをお読みください。一部のオプションは他のオプションと組み合わせるとより効率的であり、一部のオプションはすべてのCPUアーキテクチャでは使用できません。 (CPUが悪いからではなく、そのCPUのLinuxポートが十分に設計されていないためです)。
(ここには一般的な原則があります。拒否したいものよりも許可したいもののリストを作成できる場合は安全です。することができます/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によって受信されるネットワークソケットになり、他のものに接続することはできません。これは、特定のポートでのみリッスンして別のサーバーに接続する必要がない単純なサーバーの場合に便利です。 (ファイルシステム固有のオプションも使用されなくなる可能性があるため、必要なRootDirectory
バイナリとライブラリを含む新しいルートディレクトリを設定するためにこれ以上気にする必要はありません。)
最新のsystemdバージョン(v232以降)もこれをサポートしていますDynamicUser=yes
。ここで、systemd は、サービスの実行中にのみサービス・ユーザーを自動的に割り当てます。つまり、サービスの永続ユーザーを登録する必要がなく、サービスがStateDirectory
、および以外のLogsDirectory
ファイルシステムの場所に書き込まない限りCacheDirectory
(ユニットファイルでこれを宣言することもできます。もう一度確認してください。man 5 systemd.exec
)、systemdが管理する項目は動的です。ユーザーに正しく割り当てられていることに注意してください。