権限のないユーザーとしてrootコマンドを実行するためのソリューション-Sudo 'ing script-簡単にセキュリティ違反の可能性を開き、予期しない動作と結果(これはすべての場合にも当てはまります) setuid
を使用したバイナリラッパーなどの他のソリューション
このように、visudoを使用してスクリプトが追加されたことは明らかです。
www-data ALL=(ALL) NOPASSWD: /usr/local/sbin/mycommand
chown root:root mycommand; chmod 700 mycommand
)root:root
と755
モードDefaults env_reset
in /etc/sudoers
を設定する必要があります(?help here here)Sudoを使用したスクリプトを保護するために他に何ができますか?
スクリプトを保護するための基準のリストを少し修正します。 /etc/sudoers
のこれまたは同様のエントリを考えてみます。
www-data ALL=(ALL) NOPASSWD: /usr/local/sbin/mycommand
スクリプトは次のように記述できます。
PATH
を定義する必要がありますlogger
と考えてください)さらに、多くの場合、スクリプトをrootとして実行する必要はありません-スクリプトは他のアカウントに対してsetgidまたはsetuidを実行できます。一般的なケースでは、これらのオプションを検討して、スクリプトへの完全なrootアクセスを許可しないようにします。
SELinux環境の場合、スクリプトが予期しない動作をしないようにするポリシーを作成できる可能性があります。 CAP_NET_ADMINなどの機能は、包括的なroot権限よりも細かく、検討する価値があります。
単一のIPv4アドレスを検証してiptables
に渡したいという特定のケースでは、might一連の非特定オクテットとしてのIPアドレスの検証を回避できます。この場合、iptables
自体が実際のIPアドレスではないものをすべて拒否することがわかっているため、444.555.666.999はもっともらしいものとして受け入れられる可能性があります。極端な場合、RE /^[0-9.]+$/
に一致するだけで値をiptables
に渡しても問題ないと判断するかもしれません。一方、StackExchangeと その他の場所 には、IPアドレスの検証の問題に対応する answers がたくさんあります。いくつかは他よりも優れています。
考慮すべき特殊なケースは、RFC1918アドレス、マルチキャストアドレス、および独自の外部IPアドレス範囲です。ああ、以前はクラスEと呼ばれていた予約ブロックです。IPv6サポートは必要ですか?
スクリプトが1分間に数百回呼び出されるとどうなりますか?この不測の事態に備える必要がありますか? iptables
チェーンはオーバーフローしますか?チェーンに何百ものルールが必要になると思われる場合は、線形リストではなく、[ ipset
extension to iptables
を使用する方が効率的です。 。これが 良いチュートリアル です。保護に関しては、ルールセットを通過するトラフィックを大幅に遅くすることなく実行できる同様のルールの数千(そうでない場合は 数万 )のセットを構築できます。
突然、単純明快な要件は非常に複雑になります。
名前付きパイプアプローチ。ルートとして、実行します
mkfifo -m 666 /tmp/foo
/tmp/readpipe.sh &
そして、ユーザーwww-dataとしてパイプに書き込むことができます
echo test >>/tmp/foo
最も単純な形式のreadpipe.sh(汚染のあるPerlの方が良いでしょう):
#!/bin/sh
while read A </tmp/foo
do
echo received $A
done
最良のことの1つは、sudoers
ファイルで「Digest_Spec」の可能性を使用して、実行可能ファイルのチェックサムを検証することです
Manページの抜粋:
コマンド名の前にDigest_Specが付いている場合、コマンドは、指定されたSHA-2ダイジェストを使用して検証できる場合にのみ、正常に一致します。
Opensslを使用して、チェックサムを生成します。
$ openssl dgst -sha224 /usr/local/sbin/mycommand SHA224(/usr/local/sbin/mycommand)= 52246fd78f692554c9f6be9c8ea001c9131c3426c27c88dbbad08365
次に、sudoersファイルで(同じ行に):
www-data ALL=(ALL) NOPASSWD:
ssha224:52246fd78f692554c9f6be9c8ea001c9131c3426c27c88dbbad08365
/usr/local/sbin/mycommand
呼び出し元のユーザーがsetuidプロセスの動作に影響を与える可能性があるいくつかの方法を考えてみましょう。考慮すべき事項を3つのグループに分けます。1)プログラム自体、2)プログラムへの入力、3)プログラムが実行される環境です。
バイナリ:非特権ユーザーが実行されるバイナリを変更できる場合、これは特権プロセスを変更する簡単な方法です。これには、プログラムファイルへのパスがユーザーが書き込み可能なディレクトリとシンボリックリンクを通過する場合が含まれます。権限のないユーザーがプログラムファイルとそのパスに書き込みできないようにすることは必須です。 (そしてSudo
はチェックしていないようです。)
Setuidビットはパスではなくiノードのプロパティであるため、setuidバイナリは実際にはこの変更による影響を受けません。そのため、シンボリックリンクのトリックは機能しません。 (また、一部のLinuxは、別のユーザーがファイルに書き込むとsetuidビットを落とすようですが、私はそれを当てにしません。)
Inputの問題には、標準入力からのデータ、コマンドライン引数など、プログラムが機能して使用するすべての入力が含まれます。
プログラムがユーザーからの入力を必要とする場合(常に1つのことだけを行うのではなく)、これを回避することはできません。ネットワークサービスも、同様に入力に注意する必要があります。 (例として、SQLインジェクションなどを目撃します。)言うまでもなく、すべてのデータがテキストであり、すべてのテキストが1つの引用符で囲まれているシェルスクリプトなどでは、入力処理は特に難しいと思います。
入力が機密である場合は、コマンドライン引数などの問題がシステム上の他のユーザーに表示されることを考慮する場合があります。
環境はより広い問題です。明らかに、環境変数が含まれており、PATH
(実行するサブプロセスを変更できる)、LC_*
およびPOSIXLY_CORRECT
(シェルコマンドの出力形式を変更する可能性があります)、HOME
(アクセスに使用される可能性がある)などが含まれます。ファイル)、およびLD_*
(ダイナミックローダーの動作を変更する)などがあります。それらは簡単なことです。
ただし、リソースの制限、Linux cgroup、chroot、SELinuxコンテキスト、名前空間などを考慮してください。スタックの使用やプロセス数に厳しい制限を設定すると、特権プロセスが予期しない時点でクラッシュしたり、サブプロセスの起動に失敗したりすることがあります。プロセスが一部のリソースをロックした後、コミットしてロックを解除する前に、予期しないクラッシュが発生する可能性があります...
(ただし、後者の多くは非特権ユーザーが変更できないため、重大な問題ではない可能性があります。制限された環境からアクセス可能なsetuid実行可能ファイルは、制限された環境に適切に対処する必要がある場合があります。)
少なくともあなたはすべきです
PATH
を既知の値に設定するなど、環境をリセットします。絶対パスを使用することは安全だと感じますが、検索パスがわかっている場合にどのような影響があるかはわかりません。 Sudo
のenv_reset
はそれを行う必要があります。LD_*
変数は、それらを設定解除する機会を得る前に動的リンカーによって処理されますが、リンカーはsetuidプロセスではそれらを無視する必要があります。)理論的には、従来の環境で「安全な」setuidプログラムまたはSudo-ranプログラムを作成することは可能ですが、あまり一般的ではないシステム固有の機能を検証するのは難しい場合があります。
(ちなみに、多くのシステムにはpasswd
、su
、Sudo
自体がsetuidされているものの、比較的安全とは見なされていないため、setuidプログラムはalwaysでセキュリティ侵害を簡単に開くことはできません。 。)
Sudoまたはsetuid以外の他の可能性は、パイプ(またはソケット)を介して特権プロセスと通信することです。これには、実行中のバイナリが簡単に保護され、その実行環境が既知であり、権限のないユーザーがバイナリに影響を与えることができないという利点があります。
ただし、パイプを使用すると、すべてのライターからの入力が分離せずにスタックされます。改行で区切るリクエストを定義することもできますが、誰かがパイプに部分的な行を書き込んで、別のプロセスからの次のリクエストにデータを付加することができます。また、パイプは双方向通信を簡単に許可しないため、特権プロセスからステータス応答を取得することは簡単ではありません。
ソケットにはこの問題はありませんが、通常のファイルシステム関数からはアクセスできません。代わりに、ソケット関数を介してアクセスする必要があります。 (つまり、echo foo > /my/socket
は機能しません。socat
はスクリプトで役立つ場合があります)。
Sudoを利用したスクリプトを保護するために他に何ができるか:PAM-プラグ可能な認証モジュールを使用します。
PAM管理者ガイド: http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_SAG.html
PAMモジュール作成者向けガイド: http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_MWG.html
PAMアプリケーション開発者ガイド: http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_ADG.html
また、システムの/usr/share/doc/packages/pam/pdf
をチェックして、システムのPAMのバージョンに関連するこれらのドキュメントを確認してください。
PAMはLinuxの基本的なセキュリティメカニズムの1つです。これは、多くのことを保護およびロックダウンするために使用されます。2つの例は、ログインプロセスとパスワード変更プロセスです。最小文字数や有効期限などのパスワード制限を実施する場合、それはPAMで行われます。 PAMがコアシステムプロセスに十分である場合、それは確かにスクリプトに十分です。まず、PAMシステム管理ガイドを参照して、すでに活用できるもの、いくつかの例を理解してください。
pam_time:ユーザーを認証しませんが、代わりに、システムや特定のアプリケーションへの1日のさまざまな時間、特定の日のアクセス、またはさまざまな端末回線へのアクセスを制限します。このモジュールは、名前、時刻、曜日、ユーザーが申請しているサービス、ユーザーがリクエストを送信している端末に基づいて、(個々の)ユーザーへのアクセスを拒否するように構成できます。
pam_env:呼び出されたときに環境変数の設定または設定解除を引き起こします。これを使用して、pamモジュールを作成するときに利点があります。
pam_localuser:通常、ネットワークのユーザーのサブセットと特定のワークステーションにローカルないくつかのアカウントを含む、サイト全体のログインポリシーの実装に役立ちます。 pam_localuserとpam_wheelまたはpam_listfileを使用することは、ローカルユーザーまたはネットワークのユーザーのサブセット、あるいはその両方へのアクセスを制限する効果的な方法です。
リストが続く、システム管理者のガイドを参照し、必要に応じて使用してください。
これも便利な場合があります: http://freecode.com/projects/pam_script/
ここから、モジュールライターのガイドとアプリ開発ガイドを読む必要があります。これがPAM ...pluggable認証モジュールの目的です。あなたは効果的にコードを書いています、そしてあなたがまだなら、あなたが終わったときにプログラマーになるでしょう。これは、Microsoft Windowsのように有効/無効にするチェックボックスをクリックする「IT」のものではありません。 PAMを使用する理由は、システム管理者がセキュリティ上の理由でモジュールをプラグインして(場合によっては簡単で、場合によっては記述しなくてもよいため)、何でも実行できるようにするためです。たとえば、ユーザーがpasswd
を使用して自分のパスワードを変更した場合、セキュリティの観点からPAMが使用され、パスワードを変更するために「Sudo passwd」と入力しません。 /usr/bin/passwd
と同じように、PAMを適切に使用し、スクリプトの所有権とSUID/GUIDを設定すれば、スクリプトで実行する必要がある内容によっては、Sudoさえ必要ない場合があります。
これを保護するために他に何ができるかを[自分自身]に尋ねた場合、何かを行うための最良の方法ではないことを示している可能性があります。この場合、Sudoを使用して、スクリプト/実行可能ファイルを実行するための昇格された特権を付与します。代わりに、Linuxがすでにこのようなことをどのように処理するかについて確立されたメカニズムを調べてください...ポイントの場合、ユーザーが/usr/bin/passwd
を使用して、rootが所有し、root権限が必要な/etc/passwd
および/etc/shadow
ファイルを編集します変更されます。 PAMを使用すると、ユーザーID、グループID、ローカルユーザーアカウント、特定の時間などに基づいて、スクリプトを実行できるユーザーを制限できます。さらに、それらのユーザーのみを含むスクリプトを実行することのみを目的として、独自のパスワードを使用して別のグループアカウントを作成できることを確認し、スクリプトを実行するためにrootパスワードを指定しないでください。 rootにsuできるユーザーのみ、wheelグループのスキームに従います。お役に立てれば。
これを追加します:
スクリプトを直接呼び出さないでください。ただし、2次スクリプトを呼び出すには、最初のスクリプトを使用してログを作成します
#!/bin/bash
[ "$USER" != "www-data" ] && exit
set -a
Sudo realscript &>/var/log/myscript.log
そして脚本:
[ "$USER" != "root" ] && exit
Sudoでは、realscriptを、使用しているように呼び出されたスクリプトではなく、Sudoを許可するものとして配置します。
そして、www-dataが所有しているとしてmyscript.logをタッチしますが、222の権限があります(書き込みのみ可能です!)。 cronでログのバックアップを行います。
www-dataにmyscriptの内容を表示させないで、実行するだけです!
chmod 111 mylogscript
chmod 111 myrealscript
ユーザーにスクリプトを読み取らせたくないが、実行するだけなので、アクセス許可111は適切です。
可能であれば、シェルスクリプトをコンパイルしてみてください:
shc mylogscript
shc myrealscript
はい、shcはシェルコンパイラなので、スクリプトをバイナリに変換できます。安全ですが、場合によっては不安定になるため、注意してください。
$ 1 $ 2のようなシェルスクリプト内のパラメーターを使用しないようにしてください。これはスクリプトインジェクションに使用できます。その代わりに、環境変数をエクスポートしようとするのではなく、シェルが見ることができる、または一時ファイルです。ある種のopenssl暗号化でパラメータを使用するか、すべて使用しないか(この投稿を参照してください: opensslでphpなどのパスワードをコマンドラインで暗号化する方法
アプローチが良いかどうかはさておき、mycommand
がインタラクティブな場合は、noexec
ディレクティブを使用してシェルエスケープを禁止する必要があります。これは、exec()
システムコールを事前設定して何もしないようにすることで、他のコマンドの実行を防ぎます。 (これは、LD_PRELOADのメカニズムによって実現されます。Sudo.conf(5)を参照してください。)警告:これは完全なものではありません-mycommand
が静的にリンクされている場合、これは機能しません。