내 스크립트에 대한 구성 파일을 만들어야합니다. 여기 예가 있습니다.
스크립트:
#!/bin/bash
source /home/myuser/test/config
echo "Name=$nam" >&2
echo "Surname=$sur" >&2
내용 /home/myuser/test/config
:
nam="Mark"
sur="Brown"
작동합니다!
내 질문 : 이것이 올바른 방법입니까 아니면 다른 방법이 있습니까?
내 스크립트에 대한 구성 파일을 만들어야합니다. 여기 예가 있습니다.
스크립트:
#!/bin/bash
source /home/myuser/test/config
echo "Name=$nam" >&2
echo "Surname=$sur" >&2
내용 /home/myuser/test/config
:
nam="Mark"
sur="Brown"
작동합니다!
내 질문 : 이것이 올바른 방법입니까 아니면 다른 방법이 있습니까?
답변:
source
임의의 코드를 실행하므로 안전하지 않습니다. 이는 걱정할 사항이 아니지만 파일 사용 권한이 올바르지 않은 경우 파일 시스템 액세스 권한이있는 공격자가 다음과 같이 보안이 설정된 스크립트에 의해로드 된 구성 파일에 코드를 삽입하여 권한있는 사용자로 코드를 실행할 수 있습니다. 초기화 스크립트.
지금까지 내가 찾은 최고의 솔루션은 서투른 재발견 솔루션입니다.
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 /
됩니다 $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
내 코드에서 보안 취약점을 발견하면 회신하십시오.
*
입력을 올바르게 처리하지 못하지만 Bash에서 해당 문자를 잘 처리한다는 것입니다.
my\\password
Mac 및 Linux 모두에서 Bash 3 이상과 호환되는 깨끗하고 이식 가능한 버전이 있습니다.
모든 셸 스크립트에서 복잡하고 복잡한 중복 된 "기본"구성 기능이 필요하지 않도록 모든 기본값을 별도의 파일로 지정합니다. 또한 기본 폴백을 사용하거나 사용하지 않고 읽을 수 있습니다.
config.cfg :
myvar=Hello World
config.cfg.defaults :
myvar=Default Value
othervar=Another Variable
config.shlib (이것은 라이브러리이므로 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
테스트 스크립트 설명 :
printf
라인은 무엇입니까? 글쎄, 그것은 당신이 알아야 할 것입니다 : echo
당신이 통제 할 수없는 텍스트를 인쇄하기위한 나쁜 명령입니다. 큰 따옴표를 사용하더라도 플래그를 해석합니다. myvar
(in config.cfg
)을 (를 ) 설정 -e
하면 빈 줄 echo
이 표시됩니다. 이는 플래그라고 생각 하기 때문 입니다. 그러나 printf
그 문제는 없습니다. 는 printf --
"이 인쇄 및 플래그 등 아무것도 해석하지 않는다"라는, 그리고는 "%s\n"
뒤에 개행 문자의 문자열로 출력 형식 "라고, 그리고 마지막으로 최종 매개 변수는 형식의 printf의 값입니다.myvar="$(config_get myvar)";
. 화면에 인쇄하려는 경우 printf를 사용하여 사용자 구성에있을 수있는 에코 호환되지 않는 문자열에 대해 완전히 안전합니다. 그러나 사용자가 제공 한 변수 가 반향하고있는 문자열의 첫 번째 문자 가 아닌 경우 반향은 괜찮습니다 . "플래그"가 해석 될 수있는 유일한 상황이므로 echo "foo: $(config_get myvar)";
"foo"는 그렇지 않기 때문에 안전합니다. 대시로 시작하므로 나머지 문자열도 플래그가 아니라고 에코에 알립니다. :-)config.cfg.defaults
전화 할 때 그것들을 정의하는 대신에 포기했다 $(config_get var_name "default_value")
. tritarget.org/static/…
구성 파일을 구문 분석하고 실행하지 마십시오.
현재 매우 간단한 XML 구성을 사용하는 직장에서 응용 프로그램을 작성 중입니다.
<config>
<username>username-or-email</username>
<password>the-password</password>
</config>
쉘 스크립트 ( "응용 프로그램")에서 이것은 사용자 이름을 얻기 위해 수행하는 것입니다 (더 많거나 적은, 쉘 함수에 넣었습니다).
username="$( xml sel -t -v '/config/username' "$config_file" )"
이 xml
명령은 대부분의 Unices 에서 사용할 수있는 XMLStarlet 입니다.
응용 프로그램의 다른 부분도 XML 파일로 인코딩 된 데이터를 처리하므로 XML을 사용하므로 가장 쉽습니다.
JSON을 선호한다면 jq
쉘 JSON 파서를 사용하기 쉽습니다.
내 구성 파일은 JSON에서 다음과 같습니다.
{
"username": "username-or-email",
"password": "the-password"
}
그런 다음 스크립트에서 사용자 이름을 얻습니다.
username="$( jq -r '.username' "$config_file" )"
eval
여러 값을 설정하는 데 사용 하는 경우 구성 파일의 선택된 부분을 실행하고 있습니다 :-).
eval
아무것도 필요가 없습니다 . 기존 파서에서 표준 형식을 사용할 때 (외부 유틸리티 임에도 불구하고) 성능 저하는 견고성, 코드 양, 사용 편의성 및 유지 관리 성과 비교할 때 무시할 만합니다.
가장 일반적인, 효율적이고 올바른 방법은 사용하는 것입니다 source
, 또는 .
속기의 형태로. 예를 들면 다음과 같습니다.
source /home/myuser/test/config
또는
. /home/myuser/test/config
그러나 고려해야 할 사항은 추가 코드를 삽입 할 수있는 경우 외부에서 제공하는 추가 구성 파일을 사용하면 발생할 수있는 보안 문제입니다. 이 문제를 감지하고 해결하는 방법에 대한 자세한 내용은 http://wiki.bash-hackers.org/howto/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
내 시나리오에서 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
스크립트를보다 견고 하게하고 이상한 모양이나 정의가 아닌 줄을 필터링하여 줄 끝에서 끊지 않을 수는 있지만 현재로서는 충분합니다.