web-dev-qa-db-ja.com

ルート対応スクリプトに変数を安全に渡す方法は?

この質問は完全に一般的であり、私の状況に当てはまるだけでなく...私は小さなbusyboxアプライアンスを持っており、root以外のユーザーがroot権限で特定のスクリプトを実行できるようにします。たとえば、DHCPを有効にするこの小さなスクリプトのようなもので、コマンドライン(!!)で送信する唯一の変数($1)は、送信するホスト名です。

#!/bin/bash
udhcpc -b -i eth0 -h $1

このようにudhcpcを実行するにはルートアクセスが必要なので、これを行うには、次の行を含むように/etc/sudoersを変更する予定です。

joe ALL = NOPASSWD: /path/to/enable_dhcp.sh

これにより、「joe」は次のコマンドを実行するだけで、root権限でそのスクリプトを簡単に実行できるようになります。

Sudo /path/to/enable_dhcp.sh

パスワードの入力を求められない(joeがこれをスクリプト化できるようにしたいので、これが必要です)。

さて..私知っている(または少なくとも私がそう思う)root権限で簡単に実行できるスクリプトで$1を使用することは、好きなものを挿入できるので恐ろしい考えですそれ。

だから...これに対処するための最良の方法は何ですか? joeにroot権限でやりたいことをさせ、変数を渡せるようにするには(または、環境変数のように効果的にそうすることができます)、インジェクション攻撃に広くさらされることはありませんか?

13
Russ

Sudoでシェルスクリプトを実行しても安全ですSudoが環境をリセットするように構成されている場合。逆に、Sudoが環境をリセットしない場合、スクリプトがそのパラメーターを使用していなくても、シェルスクリプトの実行は安全ではありません( シェルスクリプトでsetuidを許可する を参照) 。 Defaults env_reset/etc/sudoersがあること、またはこのオプションがコンパイル時のデフォルトであることを確認してください(Sudo sudo -V | grep envにはReset the environment to a default set of variablesを含める必要があります)。

スクリプトパラメータを使用しても特に危険はありません。 $1は文字列です。確認する必要があるのは、文字列として使用していることだけです。 (たとえば、eval "$1"を実行しないでください。)明らかに、ここでは、変数の内容について推測しないこと、および すべての変数を二重引用符で囲むことが特に重要です。置換 (つまり、"$1"ではなく$1を書き込みます)。変数の置換を二重引用符で囲むことは、特権で実行されているスクリプトに固有のものではなく、常に実行する必要があることに注意してください。

udhcpcがホスト名のように見えないもので何をするかに応じて、パラメータをさらに検証することをお勧めします。たとえば、これは最初の構文チェックを実行します。

#!/bin/sh
case "$1" in
  *[!:-.0-9A-Za-z]*|-*) echo 1>&2 "Badly formed Host name!"; exit 3;;
esac
udhcpc -b -i eth0 -h "$1"

渡された入力を既知の適切なパターンと照合する必要があります。

たとえば、IPアドレスが有効な入力である可能性があります。したがって、次のようなものを使用できます。

if [[ "$1" =~ ^[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9]$ ]]
then
  udhcpc -b -i eth0 -h "$1"
else
  echo "Don't mess with me pork chop."
fi

正規表現はテストされていないことに注意してください。正規表現で危険なものが許可されていないことを確認する必要があります。

5
bahamat