매개변수 주입을 피하기 위해 이 함수를 다시 작성하는 방법

매개변수 주입을 피하기 위해 이 함수를 다시 작성하는 방법

.bashrc내 파일에는 매개변수를 사용하여 SSH를 통해 원격 서버에서 스크립트를 실행할 수 있는 기능이 있습니다 .

현재 이 기능에는 다음이 포함됩니다.

function runMyScript {
    if [ $1 = "s3" ]
    then
        ssh -i "~/path/to/.pem" server.amazonaws.com "/home/ubuntu/scripts/script.sh ${1} ${2} ${3}"
    elif [ $1 = "ec2" ]
    then 
        ssh -i "~/path/to/.pem" server.amazonaws.com "/home/ubuntu/scripts/script.sh ${1} ${2}"
    else
        echo "** Run with s3 or ec2 options"
    fi
}

따라서 or 를 사용하여 runMyScript arg_1 arg_2 arg_3함수를 호출할 수 있습니다 runMyScript arg_1 arg_2.

이 함수를 더 안전하게 만들고 매개변수 삽입을 방지하려면 어떻게 다시 작성해야 합니까?

답변1

가능한 매개변수 주입을 방지하는 방법은 무엇입니까?

전달하려는 입력 유형을 찾아 매개변수에 해당 입력만 포함되어 있는지 확인하세요.

최소한 원격 쉘 관련 문자가 포함되어 있지 않은지 확인하십시오.


$1알려진 값과 비교하기 때문에 이는 큰 문제가 아닙니다. 하지만 큰따옴표를 사용해야 합니다. 그렇지 않으면 비교에서 여러 단어로 확장될 수 있으며 이를 통해 흥미로운 값이 전달될 수 있습니다( 1 -o x비교를 통과하는 것과 유사한 것).

대신 사용하십시오 if [ "$1" = "s3" ] ; then ....

$2and 의 경우 $3and 에 전달하는 것은 기본적으로 or 에 전달하는 것과 같습니다 ssh. 모든 교체는 원격으로 확장됩니다.evalsh -c

우리가 달릴 거라고 합시다 ssh somehost "echo $var". 이제 var포함된 경우 $(ls -ld /tmp)원격 명령줄은 echo $(ls -ld /tmp)원격 ls에서 실행됩니다. 변수를 큰따옴표로 묶으면 명령 확장에 도움이 되지 않지만 작은따옴표로 묶으면 도움이 됩니다. 명령이 로 기록되면 ssh somehost "echo '$var'"명령 확장이 발생하지 않습니다 .

변수 내부의 작은따옴표는 작은따옴표를 끝내기 때문에 여전히 문제가 되므로 최소한 다음 사항을 확인해야 합니다.

case "$var" in *"'"*) echo var has a single-quote; exit 1 ;; esac

전달하고 싶지 않은 특수 문자가 있는지 확인할 수도 있습니다. 달러 기호는 대부분의 확장을 시작하고 백틱은 명령 확장을 시작하며 따옴표도 내가 신뢰하지 않는 것입니다.

case "$var" in *[\'\"\$\`]*) echo var has something funny; exit 1 ;; esac

하지만 그게 전부인지는 잘 모르겠으니, 전달하고 싶은 문자를 화이트리스트에 등록해 두는 것이 좋을 것 같습니다. 문자, 숫자, 대시, 밑줄만으로 충분할 경우:

case "$var" in *[!-_a-zA-Z0-9]*) echo var has something funny; exit 1 ;; esac

이제 이것이 시작일 수 있습니다.

function runMyScript {
    case "$2" in *[!-_a-zA-Z0-9]*) exit 1 ;; esac
    case "$3" in *[!-_a-zA-Z0-9]*) exit 1 ;; esac

    if [ "$1" = "s3" ] ; then
        ssh somehost "script.sh '$1' '$2' '$3'"
    elif [ "$1" = "ec2" ] ; then 
        ssh somehost "script.sh '$1' '$2'"
    else
        echo "** Run with s3 or ec2 options"
    fi
}

function runMyScript대신 을 사용하고 있으며 runMyScript()일반 POSIX 쉘을 실행하고 있지 않습니다. Bash인 경우 패턴 일치를 재정의할 수 있습니다.테스트 [[...]], 정규식 일치 지원.

최신 버전의 Bash 에는 입력으로 재사용할 수 있는 형식으로 ${var@Q}인용된 콘텐츠를 생성하는 확장 기능도 있습니다. var작동할 수도 있지만 테스트할 만큼 새로운 bash가 없습니다.


또한 제가 쉘 언어의 가능한 모든 특징을 기억한다고 맹목적으로 믿지 마십시오.

답변2

@ikkachu의 훌륭한 답변 외에도:

evalsh -c여기서 문제는 임의의 문자열을 or 에 전달하는 것보다 더 심각합니다.

  • 실제로 명령줄을 구문 분석하기 위해 원격 호스트에서 어떤 쉘이 사용될지 알 수 없습니다.
  • 로케일은 무엇이며, 구체적으로 원격 호스트에서 어떤 문자 세트가 사용될 것인지. 로컬 시스템과 동일합니까?

귀하의 질문은 주로 하위 집합입니다원격 사용자의 로그인 셸을 모르고 SSH를 통해 임의의 간단한 명령을 어떻게 실행할 수 있습니까?

따라서 거기에 대한 대답은 여기에도 적용됩니다.

특히 sshd원격 호스트가 LC_*(많은 openssh 배포와 마찬가지로)로 시작하는 환경 변수 전달을 허용하는 경우 다음을 수행할 수 있습니다.

LC_ARG1=$1 LC_ARG2=$2 LC_ARG3=$3 ssh -o SendEnv='LC_*' host exec sh -c \
   \''exec my-script "$LC_ARG1" "$LC_ARG2" "$LC_ARG3"'\'

[A-Z]입력을 삭제하는 것은 좋은 생각이지만 C 로케일을 사용하지 않는 한 이와 같은 범위를 사용하고 싶지 않다는 점에 유의하세요. 예를 들어, 대부분의 GNU 시스템 로케일에서 Ǒ이는 해당 범위에 속하며, 예를 들어 로케일에서 zh_HK.big5hkscs이 문자는 으로 인코딩되므로 0x88 0x600x60을 백틱 문자의 ASCII(및 BIG5HKSCS) 인코딩으로 인식할 수 있습니다!

허용되는 문자를 개별적으로 나열하는 것이 좋습니다.

is_safe() case $1 in
  *[!-_.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]*) false;;
esac

또한 따옴표로 묶어야 하는 빈 문자열에 유의하세요( ''모든 일반 쉘에서 지원됨). 그리고 -일부 도구가 옵션일 수 있다는 주장에 주의하세요.

관련 정보