文字列変数を使用したシェルコマンドの保護

文字列変数を使用したシェルコマンドの保護

プログラミング言語では、単純なシェルコマンドを実行します。

cd var; echo > create_a_file_here

そして変わりやすい"create_a_file_here" ファイルを生成するディレクトリ文字列を含む変数です。今誰もがこのコード行を見ている場合は、次のような割り当てでそれを悪用することができます。

var = "; rm -rf /"

状況は本当に醜くなる可能性があります。上記の状況を回避する1つの方法は、文字列を検索することです。変わりやすいシェルコマンドを実行する前に、「;」などのいくつかの特殊文字について説明しましたが、これが可能なすべての脆弱性に対処していると思われます。

"cd var"がディレクトリだけを変更し、他のものを変更しないようにする良い方法を知っている人はいますか?

答え1

簡単な解決策:プログラム内でシェルを呼び出さないでください。絶対にしないでください。

ここの例は簡単であり、どのプログラミング言語を使用してもディレクトリの変更とファイルの作成が簡単になります。ただし、外部コマンドを実行する必要がある場合でも、通常はシェルを介して実行する必要はありません。

たとえば、Pythonは実行する代わりにをos.system("somecmd " + somearg)使用しますsubprocess.run(["somecmd", somearg])。 Cでは、代わりにand(またはそれを実行するライブラリを見つけてください)をsystem()使用してください。fork()exec()

シェルを使用する必要がある場合は、コマンドライン引数を引用するか、次のように環境を介して渡します。スティーブンの答え。また、特殊文字が気になる場合は、正しい解決策は次のとおりです。いいえ潜在的に危険な文字をフィルタリング(ブラックリスト)してみてください。維持する既知の安全な文字(許可リスト)。

機能をしっかり知っているキャラクターだけを許可すると、何かを逃す危険が減ります。最終結果は単に許可することにすることですが[a-zA-Z0-9_]、これは作業を完了するのに十分かもしれません。また、ロケールとツールセットに、äなどのöアクセント文字が含まれていないことを確認することもできます。どんなシェルでも特別とは見なされないかもしれませんが、通過することを確認するのが最善です。

答え2

私が正しく理解したら、varプログラミング言語の変数です。

"cd "プログラミング言語では、変数の内容およびの連結である文字列を解釈するようにシェルに要求します"; echo > create_a_file_here"

その場合、コンテンツがvar厳密に制御されていない場合、これはコマンドインジェクションの脆弱性です。

cd組み込み関数に単一の引数として渡されるように、シェル構文の変数1の内容を適切に引用することができます。

別のアプローチは、変数の内容を別の方法で渡すことです。 1つの確実な方法は、環境変数に渡すことです。たとえば、Cでは次のようになります。

char *var =  "; rm -rf /";
setenv("DIR", var, 1);
system("CDPATH= cd -P -- \"$DIR\" && echo something > create_a_file_here");

今回はシェルに解釈を要求したコードが修正されたので、シェルの構文でそれを正しく作成する必要があります(ここではPOSIX互換シェルであると仮定)。

  • スプリット+グローブを避けるには、シェル変数拡張を引用する必要があります。
  • 簡単に-P作る必要がありますcdchdir()
  • --(または一部のシェルで)var起動する問題を回避するには、オプションの終わりを表示する必要があります。-+
  • CDPATH環境にある場合は空の文字列に設定します。
  • echo成功した場合にのみコマンドを実行してください。cd

(少なくとも)もう一つの問題があります。もしvarそうなら-、呼び出されたディレクトリでchdirを実行しません-より早いディレクトリ(に保存されている場合$OLDPWD)であり、OLDPWD=- CDPATH= cd -P -- "$DIR"解決されるという保証はありません。したがって、次のようなものが必要です。

system(
  "case $DIR in\n"
  " (-) CDPATH= cd -P ./-;;\n"
  " (*) CDPATH= cd -P -- \"$DIR\";;\n"
  "esac && ....");

¹単にsystem(concat("cd \"", var, "\"; echo..."));次のことを行うことに注意してください。いいえ行かなければならない道、あなたはただ問題を偏らせるだけです。

たとえば、aはvar = "$(rm -rf /)"まだ問題です。

これただBourneなどのシェルからテキストを引用する信頼できる方法は、単一引用符を使用することです。そしてまた、文字列内に可能な単一引用符を書き留めます。たとえば、aをchar *var = "ab'cd"に移動しますchar *escaped_var = "'ab'\\''cd'"。つまり、allを'に置き換えて'\''その中に全体をラップします'...'

これはまだバックティック内に引用された文字列が使用されていないと仮定し、まだ、、、、...---P必要です。&&CDPATH=

答え3

プログラミング言語には、シェルコマンドを実行するよりも操作を実行するより良い方法が必要です。たとえば、cd varプログラミング言語に対応するものに置き換えるchdir (var);と値がvar

また、ディレクトリを変更する代わりに絶対パスを使用できます。使用したいディレクトリ名、スラッシュ、ファイル名をリンクするだけです。

Cでは、次のようにすることができます。

char filepath[PATH_MAX];  /* alternative constant: MAXPATHLEN */

/* Join directory name in var and the filename, guarding against exceeding PATH_MAX */
snprintf (filepath, PATH_MAX, "%s/%s", var, "create_a_file_here");

/* create an empty file/truncate an existing one */
fclose (fopen (filepath, "w") );

確かにあなたのプログラミング言語が似たようなことをすることができますか?

関連情報