8

システムアカウントで実行されるサーバーアプリケーションがあります。これは、いつでも、システム上のすべてのユーザーに代わって要求を処理するためです。これらの要求は、ファイルシステムを操作するための命令で構成されています。

ここに問題があります。プログラムは、アクションを実行するときにその特定のユーザーの特権を念頭に置く必要があります。たとえば、権限が。の場合、joe変更できないようにする必要があります。/home/larry755

現在の私の戦略はこれです

  • ファイルの所有者/グループを取得します
  • アクションを実行しようとしているユーザーのユーザーID/グループIDと比較します
  • いずれかが一致する場合(または一致しない場合)、ファイルのアクセス許可フィールドの適切な部分を使用して、アクションを許可または拒否します

これは賢明ですか?これを行う簡単な方法はありますか?

最初は、ユーザーのアカウントでアプリの複数のインスタンスを実行することを考えていましたが、特定のTCPポートでリッスンできるのは1つのインスタンスのみであるため、これはオプションではありません。

4

3 に答える 3

3

サーバーfork()を使用して、すぐsetuid(uid)にroot権限を放棄します。そうすれば、ファイル操作はあなたがなったユーザーに代わって行われます。あなたはサーバーの子なので、リクエスト(そして私は応答を想定)が続行するaccept()された子ソケットを保持します。これには(明らかに)デーモンに対するroot権限が必要です。

この場合、子にはすでに「要求」記述子があるため、プロセス間でファイル記述子を渡すことは不必要に複雑に見えます。

于 2011-01-31T06:50:32.577 に答える
3

これができる例については、sambaを見てください。sambaデーモンはrootとして実行されますが、フォークして通常のユーザーの資格情報をできるだけ早く引き継ぎます。

Unixシステムには、実際のユーザー/グループIDと実効ユーザー/グループIDの2つの別個の資格情報のセットがあります。実際のセットはあなたが実際に誰であるかを識別し、効果的なセットはあなたがアクセスできるものを定義します。移行中は実際のユーザー/グループIDがrootのままであるため、rootの場合は、有効なuid / gidを自由に変更できます(通常のユーザーを含む)。したがって、単一のプロセスでこれを行う別の方法はseteuid/gid、必要に応じてさまざまなユーザーの権限を前後に適用するために使用することです。サーバーデーモンがrootとして実行されているか、または持っているCAP_SETUID場合、これは許可されます。

ただし、気まぐれで有効なuid / gidを切り替える機能があり、アプリケーションが破壊された場合、その破壊によって、たとえば有効なuid / gidが0に戻され、重大なセキュリティの脆弱性が発生する可能性があることに注意してください。これが、実際のユーザーuid/gidを含むすべての特権をできるだけ早く永久に削除することが賢明な理由です。

このため、単一のリスニングソケットをrootとして実行し、次にフォークして、を呼び出して実際のユーザーIDと有効なユーザーIDの両方を変更するのが通常で安全setuidです。その後、元に戻すことはできません。フォークされたプロセスaccept()には、フォークであるために編集されたソケットがあります。各プロセスは、不要なファイル記述子を閉じるだけです。ソケットは、反対のプロセスでファイル記述子によって参照されるため、存続します。

自分で個別にアクセス許可を調べて強制することもできますが、これは潜在的にエラーが発生しやすく、多くのエッジケースがあり、うまくいかない可能性が高いことは明らかです(たとえば、POSIX ACLでは機能しません)。特にそれを実装しない限り)。

したがって、3つのオプションがあります。

  1. 必要なユーザーにフォークおよびsetgid()/setuid()します。通信が必要な場合は、フォークする前pipe(2)に使用してください。socketpair(2)
  2. seteuid()必要に応じてフォークしたり、周りを回ったりしないでくださいsetegid()(安全性が低い:誤ってサーバーを危険にさらす可能性が高くなります)。
  3. システムのクレデンシャルを台無しにしないでください。手動で権限の適用を行います(安全性が低い:権限が間違っている可能性が高くなります)。

デーモンと通信する必要がある場合、ソケットまたはパイプを介して通信するのは難しいかもしれませんが、最初のオプションは実際にはそれを実行するための適切な安全な方法です。たとえば、sshが特権分離を行う方法をご覧ください。また、アーキテクチャを変更して、通信の代わりにプロセスがメモリまたはディスクスペースを共有できるかどうかを検討することもできます。

ユーザーごとに個別のプロセスを実行することを検討したが、単一のリスニングTCPポートが必要であるとおっしゃいました。あなたはまだこれを行うことができます。マスターデーモンにTCPポートをリッスンさせ、各ユーザーデーモンに要求をディスパッチし、必要に応じて(たとえば、Unixドメインソケットを介して)通信するだけです。これは実際には、フォークマスターデーモンを使用するのとほぼ同じです。後者の方が実装しやすいと思います。

さらに読む:credentials(7)マンページ。Linuxにはファイルシステムuid/gidsがあることにも注意してください。これは、信号の送信などの他のものを除いて、効果的なuid/gidsとほぼ同じです。ユーザーがシェルアクセス権を持たず、任意のコードを実行できない場合は、違いを心配する必要はありません。

于 2011-02-13T23:08:35.140 に答える
2

1台のサーバーを以前のサーバーポートで実行し、システムにログインするユーザーの子プロセスを生成します。子プロセスは特権を削除し、ログインしたユーザーになりすます必要があります。これで、子は害を及ぼすことができなくなります。

于 2011-01-31T05:03:36.410 に答える