파일 이름 평가, 악?

파일 이름 평가, 악?

프로젝트를 생성하기 위한 다음 스크립트가 있습니다.

clear
version="0.0.2"
echo "Project creator"
echo "---------------"
# ask user to specify a directory (could start with spelled-out home directory)
directoryName=""
# Input must meet the following criteria: 
# 1.) No spaces at all in the directory path
# 2.) some characters must be entered
while [[ ${#directoryName} -eq 0 || $directoryName == *" "* ]]
        do
                echo -e "\nEnter the full directory of the project (no spaces):"
                read directoryName
        done
echo "You entered: $directoryName"
# uate directoryName so that the rest of the code can understand it
# create directory if it does not exist
eval mkdir "$directoryName"
# if successful
if [ $? -eq 0 ]
then
        # call executable in /home/miwarren/CPPFileCreator to create a main.cpp file to put in the folder
        $HOME/CPPFileCreator/a.out $directoryName
        # copy a run.sh file into the folder, too...
        eval cp $HOME/CPPFileCreator/run.sh $directoryName/run.sh
        # you might want to put a fileCreator.sh in the folder as well
        eval cp $HOME/fileCreator.sh $directoryName/fileCreator.sh
fi

모든 공백을 제거했습니다(삽입 공격으로 인해 안전하지 않은 각 문자열에 적어도 하나의 공백이 있다고 가정). 변수가 존재할 때 사용자가 경로 부분(예: $HOME홈 디렉터리) 을 철자하지 않아도 되기를 바랍니다.

여기서 계속 사용할 수 있나요 eval? 그렇지 않다면 어떻게 해야 합니까?

답변1

"변수가 존재할 때 사용자가 경로 부분을 철자하지 않아도 되기를 바랍니다(예: 홈 디렉토리의 경우 $HOME)."

이 작업은 다음 없이 수행할 수 있습니다 eval.

$ s='$HOME/.config'
$ s="${s//\$HOME/$HOME}"
$ echo "$s"
/home/john1024/.config

여기에는 몇 가지 제한 사항이 있습니다. 먼저 HOMES와 HOME이 모두 교체 대상 변수 이름인 경우 잘못된 매칭을 방지하기 위해 HOMES를 교체해야 합니다.앞으로집.

내보낸 모든 변수에 대체 적용

배시 사용:

while IFS== read -r name val
do
   s="${s//\$$name/$val}"
done < <(printenv)

예를 들어:

$ export A=alpha; export B=beta
$ s='$HOME/$A/$B'
$ while IFS== read -r name val; do s="${s//\$$name/$val}"; done < <(printenv)
$ echo "$s"
/home/john1024/alpha/beta

이 접근 방식은 변수 이름을 길이별로 정렬하지 않기 때문에 위에서 언급한 변수 중복 문제가 발생합니다.

변수 이름을 길이에 따라 정렬하여 이 문제를 해결할 수 있습니다.

while IFS== read -r n name val
do
   s="${s//\$$name/$val}"
done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)

사용자가 변수 이름을 입력하는 경우아니요존재하지만 초기 문자가 더 짧은 이름과 일치하면 더 짧은 이름이 대체됩니다. 이것이 중요한 경우 다음 코드를 사용하여 사용자에게 이 변수에 중괄호 표기법을 사용하도록 요구하여 이를 방지할 수 있습니다.

while IFS== read -r n name val
do
   s="${s//\$\{$name\}/$val}"
done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)

예를 들어:

$ s='${HOME}/${A}/${B}'
$ while IFS== read -r n name val; do s="${s//\$\{$name\}/$val}"; done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)
$ echo "$s"
/home/john1024/alpha/beta

답변2

여기서 사용하는 것은 의미가 없습니다 eval. 스크립트 수정 방법을 결정하기 전에,귀하의 요구 사항을 신중하게 생각하고 적어 두십시오.. 귀하의 질문을 읽어보면, 귀하가 무엇을 하고 싶은지에 대한 명확한 생각이 없고, 솔루션에서 기대하는 것이 무엇인지 알아내기 전까지는 문제를 해결하지 못할 것이 분명합니다.

모든 안전하지 않은 문자열에는 최소한 하나의 공백이 있다고 가정합니다.

아니, 심지어 가깝지도 않아요. 스크립트를 사용하면 사용자가 공백과 줄 바꿈을 포함하지 않는 모든 문자열을 입력할 수 있으므로 임의의 코드를 실행할 수 있습니다. 사용자는 대신 탭과 세미콜론을 사용할 수 있습니다. 공백이 없어도 사용자는 대체 명령을 입력할 수 있습니다.

`touch /tmp/this_is_executed`somefile
$(touch /tmp/this_is_executed)somefile

이것이 문제입니까? 그것은 당신이하고 싶은 일에 달려 있습니다. 일반 계정에서 스크립트를 실행하는 사용자가 입력을 합니까? 그렇다면 보안 문제는 없지만 스크립트가 표준 입력에서 입력을 읽는 것은 의미가 없습니다. 명령줄 인수를 사용하면 명령줄 쉘이 원하는 변수 확장을 수행합니다. 스크립트가 높은 권한으로 실행되거나 네트워크를 통해 입력을 받는 경우 이는 eval절대적으로 해롭기 때문에 그 의미를 이해할 때까지 사용해서는 안 됩니다. eval문자열을 인수로 받아들이고(인수가 여러 개인 경우 공백으로 연결됨) 이를 쉘 코드로 실행합니다. 쉘 코드를 실행하고 싶지 않다면 eval이 도구는 잘못된 것입니다.

스크립트가 권한 없는 입력을 받는 경우 변수 확장을 수행하기에 잘못된 위치입니다. 사용자 권한으로 실행되는 스크립트에 입력을 제공하는 인터페이스에서 이 작업을 수행합니다(예: 입력이 웹 브라우저에서 오는 경우 Javascript 사용). 스크립트에서 지정된 파일 이름이 사용자가 액세스할 수 있는 디렉터리에 있는지 확인해야 합니다. ..디렉터리 트리 탈출을 허용할 수 있는 기호 링크 에 주의하세요 .-파일 이름 대신 옵션으로 구문 분석할 수 있는 행간.

관련 정보