내 쉘 스크립트의 구성 파일 사용

내 쉘 스크립트의 구성 파일 사용

내 스크립트에 대한 구성 파일을 만들어야 합니다.
예는 다음과 같습니다.

스크립트:

#!/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 /

를 사용하면 이 작업이 두 번 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" )

명령 xmlstarletXML 스타, 대부분의 Unices에 적용됩니다. 일부 시스템에서는 xml.

애플리케이션의 다른 부분도 XML 파일로 인코딩된 데이터를 처리하므로 XML을 사용하는 것이 가장 쉽습니다.

JSON을 선호한다면 다음과 같습니다.jq이것은 사용하기 쉬운 쉘 JSON 파서입니다.

내 구성 파일은 JSON에서 다음과 같습니다.

{                                 
  "username": "username-or-email",
  "password": "the-password"      
}         

그런 다음 스크립트에서 사용자 이름을 가져옵니다.

username=$( jq -r .username "$config_file" )

TOML(“톰의 최소한의 언어인 것 같아요”), 여러 언어에 대한 파서 포함. 배포판의 tomlq일부로 개인적으로 가장 좋아하는 파서yqhttps://kislyuk.github.io/yq/( jq무대 뒤에서 사용됨).

구성 파일의 TOML 버전은 다음과 같습니다.

username = "username-or-email"
password = "the-password"

(문자열은 JSON으로 인코딩됩니다.)...여기에서 데이터를 가져오는 것은 JSON 사례만큼 간단합니다(문자열은 JSON tomlq위에 구축 되므로 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.

관련 정보