自分のスクリプト用の構成ファイルを作成する必要があります。ここでは例を示します。
脚本:
#!/bin/bash
source /home/myuser/test/config
echo "Name=$nam" >&2
echo "Surname=$sur" >&2
の内容 /home/myuser/test/config
:
nam="Mark"
sur="Brown"
それはうまくいきました!
私の質問:これはこれを行う正しい方法ですか、それとも他の方法がありますか?
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 /
source
を使用すると、これはecho rm -rf /
を2回実行し、実行中のユーザーの$Prompt_COMMAND
。代わりに、次のようにします。
myscript.sh(Bash 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
私のコードにセキュリティの悪用を見つけたら返信してください。
これは、MacとLinuxの両方で、Bash 3以降と互換性があるクリーンでポータブルなバージョンです。
すべてのデフォルトを別のファイルで指定し、すべてのシェルスクリプトで巨大な、雑然とした、重複した「デフォルト」設定関数が必要になるのを回避します。また、デフォルトのフォールバックを使用するか、使用しないかを選択できます。
config.cfg:
_myvar=Hello World
_
config.cfg.defaults:
_myvar=Default Value
othervar=Another Variable
_
config.shlib(これはライブラリなので、シバン行はありません):
_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
_
テストスクリプトの説明:
printf
行は何ですか?まあ、それはあなたが知っておくべきことです:echo
はあなたが制御できないテキストを印刷するための悪いコマンドです。二重引用符を使用しても、フラグを解釈します。 myvar
を_config.cfg
_に_-e
_に設定すると、空の行が表示されます。これは、echo
がフラグと見なすためです。しかし、printf
にはその問題はありません。 _printf --
_は「これを出力し、何もフラグとして解釈しない」と言い、_"%s\n"
_は「末尾に改行を含む文字列として出力をフォーマットし、最後に最後のパラメーターがフォーマットするprintf。myvar="$(config_get myvar)";
のように、通常どおりに値を割り当てます。それらを画面に印刷する場合は、printfを使用して、ユーザー構成にあるエコーと互換性のない文字列に対して完全に安全にすることをお勧めします。しかし、ユーザーが指定した変数がエコーしない文字列の最初の文字でない場合、エコーは問題ありません。これは「フラグ」が設定される唯一の状況であるためです。 "foo"がダッシュで始まっておらず、残りの文字列もそのためのフラグではないことをエコーに通知するため、echo "foo: $(config_get myvar)";
のようなものは安全です。 :-)構成ファイルを解析し、実行しないでください。
現在、非常に単純なXML構成を使用するアプリケーションを作成しています。
<config>
<username>username-or-email</username>
<password>the-password</password>
</config>
シェルスクリプト(「アプリケーション」)では、これはユーザー名を取得するために行うことです(多かれ少なかれ、シェル関数に入れました)。
username="$( xml sel -t -v '/config/username' "$config_file" )"
xml
コマンドは XMLStarlet であり、ほとんどのUnicesで使用できます。
アプリケーションの他の部分もXMLファイルにエンコードされたデータを処理するため、私はXMLを使用しています。
JSONを好む場合は、シェルJSONパーサーを簡単に使用できる jq
があります。
私の構成ファイルは、JSONでは次のようになります。
{
"username": "username-or-email",
"password": "the-password"
}
そして、スクリプトでユーザー名を取得します。
username="$( jq -r '.username' "$config_file" )"
最も一般的で効率的かつ正しい方法は、source
、または.
を省略形として使用することです。例えば:
source /home/myuser/test/config
または
. /home/myuser/test/config
ただし、追加のコードを挿入できる場合、追加の外部ソースの構成ファイルを使用すると発生する可能性があるセキュリティの問題について検討する必要があります。この問題を検出して解決する方法などの詳細については、 http://wiki.bash-hackers.org/howtoの「Secure it」セクションを参照することをお勧めします/ conffile#secure_it
私はスクリプトでこれを使用します:
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
/eval
を一切使用しないため、これは完全に安全です。
これは簡潔で安全です:
# Read common vars from common.vars
# the incantation here ensures (by env) that only key=value pairs are present
# then declare-ing the result puts those vars in our environment
declare $(env -i `cat common.vars`)
-i
は、common.vars
からのみ変数を取得することを保証します
更新:セキュリティのイラストは
env -i 'touch evil1 foo=omg boo=$(touch evil2)'
タッチされたファイルは生成されません。 Macでbashを使用して、つまりbsd envを使用してテストされています。
私のシナリオでは、source
または.
で問題ありませんでしたが、構成された変数よりも優先されるローカル環境変数(つまり、FOO=bar myscript.sh
)をサポートしたいと考えました。私はまた、構成ファイルをユーザーが編集可能で、ソースの構成ファイルに慣れているユーザーにとって快適であり、非常に小さなスクリプトの主な目的に気を取られないように、できるだけ小さく/シンプルに保つことも望んでいました。
これは私が思いついたものです:
CONF=${XDG_CONFIG_HOME:-~/config}/myscript.sh
if [ ! -f $CONF ]; then
cat > $CONF << CONF
VAR1="default value"
CONF
fi
. <(sed 's/^\([^=]\+\) *= *\(.*\)$/\1=${\1:-\2}/' < $CONF)
本質的に-それは変数定義をチェックし(空白について非常に柔軟ではない)、値がその変数のデフォルトに変換されるようにそれらの行を書き換え、上記のXDG_CONFIG_HOME
変数のように、変数が見つかった場合は変更されません。この変更されたバージョンの構成ファイルを入手して続行します。
今後の作業でsed
スクリプトをより堅牢にし、奇妙に見える行や定義ではない行を除外するなどして、行末のコメントで中断しないようにすることができますが、今のところこれで十分です。