私のスクリプトの設定ファイルを作成する必要があります。
例は次のとおりです。
スクリプト:
#!/bin/bash
source /home/myuser/test/config
echo "Name=$nam" >&2
echo "Surname=$sur" >&2
コンテンツ/home/myuser/test/config
:
nam="Mark"
sur="Brown"
動作します!
私の質問:この方法が正しいのですか、それとも別の方法がありますか?
答え1
source
任意のコードを実行できるので安全ではありません。これは問題ではないかもしれませんが、ファイル権限が間違っている場合、ファイルシステムへのアクセス権を持つ攻撃者は、initスクリプトなどの他のセキュリティスクリプトによって生成されたファイルにコードを挿入してアクセス権を得る可能性があります。
これまで私が見つけた最高のソリューションは、ホイールソリューションを不器用に再作成したことです。
myscript.conf
password=bar
echo rm -rf /
PROMPT_COMMAND='echo "Sending your last command $(history 1) to my email"'
hostname=localhost; echo rm -rf /
を使用すると、これは2回実行され、source
代わりに次の操作が行われます。echo rm -rf /
$PROMPT_COMMAND
myscript.sh(パンチ4)
#!/bin/bash
typeset -A config # init array
config=( # set default values in config array
[username]="root"
[password]=""
[hostname]="localhost"
)
while read line
do
if echo $line | grep -F = &>/dev/null
then
varname=$(echo "$line" | cut -d '=' -f 1)
config[$varname]=$(echo "$line" | cut -d '=' -f 2-)
fi
done < myscript.conf
echo ${config[username]} # should be loaded from defaults
echo ${config[password]} # should be loaded from config file
echo ${config[hostname]} # includes the "injected" code, but it's fine here
echo ${config[PROMPT_COMMAND]} # also respects variables that you may not have
# been looking for, but they're sandboxed inside the $config array
myscript.sh(Mac / Bash 3と互換性があります)
#!/bin/bash
config() {
val=$(grep -E "^$1=" myscript.conf 2>/dev/null || echo "$1=__DEFAULT__" | head -n 1 | cut -d '=' -f 2-)
if [[ $val == __DEFAULT__ ]]
then
case $1 in
username)
echo -n "root"
;;
password)
echo -n ""
;;
hostname)
echo -n "localhost"
;;
esac
else
echo -n $val
fi
}
echo $(config username) # should be loaded from defaults
echo $(config password) # should be loaded from config file
echo $(config hostname) # includes the "injected" code, but it's fine here
echo $(config PROMPT_COMMAND) # also respects variables that you may not have
# been looking for, but they're sandboxed inside the $config array
自分のコードでセキュリティの脆弱性が見つかった場合は返信してください。
答え2
構成ファイルを解析して実行しないでください。
私は現在、非常に単純なXML構成を使用するアプリケーションを作成しています。
<config>
<username>username-or-email</username>
<password>the-password</password>
</config>
シェルスクリプト(「アプリケーション」)からユーザー名を取得する方法は次のとおりです(ほとんどのシェル関数に入れます)。
username=$( xmlstarlet sel -t -v '/config/username' "$config_file" )
コマンドxmlstarlet
はXMLスター、ほとんどのUnicesに適用されます。一部のシステムではxml
。
アプリケーションの他の部分もXMLファイルでエンコードされたデータを処理するため、XMLを使用するのが最も簡単です。
JSONを好む場合は、次のようになります。jq
これは使いやすいシェルJSONパーサーです。
私の設定ファイルはJSONで次のようになります。
{
"username": "username-or-email",
"password": "the-password"
}
その後、スクリプトからユーザー名を取得します。
username=$( jq -r .username "$config_file" )
TOML(「トムの最小限の言語だと思います」)、複数の言語のパーサーを含む。ディストリビューションのtomlq
一部として個人的に好きなパーサーyq
https://kislyuk.github.io/yq/(jq
舞台裏で使用)。
構成ファイルのTOMLバージョンは次のとおりです。
username = "username-or-email"
password = "the-password"
(文字列はJSONでエンコードされています。)...ここからデータを取得するのはJSONケースと同じくらい簡単です(文字列はJSONtomlq
の上に構築されているためjq
)。
username=$( tomlq -r .username "$config_file" )
答え3
これは、MacとLinuxのBash 3以降と互換性のあるクリーンで移植可能なバージョンです。
すべてのシェルスクリプトで大規模で混乱し、重複した「デフォルト」構成機能を使用する必要がないように、単一ファイルにすべてのデフォルト値を指定します。デフォルトの置換を含めるか含めないで読み取りを選択できます。
構成ファイル:
myvar=Hello World
config.cfg.default:
myvar=Default Value
othervar=Another Variable
構成ファイル(これはライブラリなので、shebang-lineはありません):
config_read_file() {
(grep -E "^${2}=" -m 1 "${1}" 2>/dev/null || echo "VAR=__UNDEFINED__") | head -n 1 | cut -d '=' -f 2-;
}
config_get() {
val="$(config_read_file config.cfg "${1}")";
if [ "${val}" = "__UNDEFINED__" ]; then
val="$(config_read_file config.cfg.defaults "${1}")";
fi
printf -- "%s" "${val}";
}
test.sh(または設定値を読み取るスクリプト):
#!/usr/bin/env bash
source config.shlib; # load the config library functions
echo "$(config_get myvar)"; # will be found in user-cfg
printf -- "%s\n" "$(config_get myvar)"; # safer way of echoing!
myvar="$(config_get myvar)"; # how to just read a value without echoing
echo "$(config_get othervar)"; # will fall back to defaults
echo "$(config_get bleh)"; # "__UNDEFINED__" since it isn't set anywhere
テストスクリプトの説明:
- 気づくみんなtest.shでは、config_getの使用法は二重引用符で囲まれています。各 config_get を二重引用符で囲み、変数値のテキストをいいえフラグで誤解された。これにより、構成値の連続した複数のスペースなど、スペースを正しく保存することができます。
printf
その行は何ですか?まあ、あなたはこれに注意する必要があります:echo
これはあなたが制御できないテキストを印刷するための誤ったコマンドです。二重引用符を使用してもフラグを解釈します。myvar
(でconfig.cfg
)をに設定するとフラグと見なされ、空白-e
行が表示されます。echo
しかし、printf
そのような問題はありません。printf --
「これを印刷し、何もフラグとして解釈しないでください」と言い、「出力を末尾の改行"%s\n"
文字列にフォーマットします。printfの最後の引数はフォーマットする値です。- 値を画面に表示したくない場合は、正常に割り当ててください
myvar="$(config_get myvar)";
。たとえば、画面に印刷するには、printfを使用して、次のすべてのものに対して完全に安全であることをお勧めします。互換性のない文字列をエコーすることに関連するユーザー設定に存在できます。しかし、ユーザーが提供した変数echoいいえエコーする文字列の最初の文字は、「フラグ」が解釈される唯一のケースなので、echo "foo: $(config_get myvar)";
「foo」はダッシュで始まらないので、このような文字は安全です。したがって、文字列の残りの部分もダッシュで始まるとechoに通知します。ロゴでもありません。 :-)
答え4
私のスクリプトはこれを使用します。
sed_escape() {
sed -e 's/[]\/$*.^[]/\\&/g'
}
cfg_write() { # path, key, value
cfg_delete "$1" "$2"
echo "$2=$3" >> "$1"
}
cfg_read() { # path, key -> value
test -f "$1" && grep "^$(echo "$2" | sed_escape)=" "$1" | sed "s/^$(echo "$2" | sed_escape)=//" | tail -1
}
cfg_delete() { # path, key
test -f "$1" && sed -i "/^$(echo $2 | sed_escape).*$/d" "$1"
}
cfg_haskey() { # path, key
test -f "$1" && grep "^$(echo "$2" | sed_escape)=" "$1" > /dev/null
}
区切り文字を含めることができないキーストロークを除くすべての文字の組み合わせをサポートする必要があります=
。他はすべて動作します。
% cfg_write test.conf mykey myvalue
% cfg_read test.conf mykey
myvalue
% cfg_delete test.conf mykey
% cfg_haskey test.conf mykey || echo "It's not here anymore"
It's not here anymore
source
さらに、orを使用しないので完全に安全ですeval
。