.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 ...
.
$2
and 의 경우 $3
and 에 전달하는 것은 기본적으로 or 에 전달하는 것과 같습니다 ssh
. 모든 교체는 원격으로 확장됩니다.eval
sh -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의 훌륭한 답변 외에도:
eval
sh -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 0x60
0x60을 백틱 문자의 ASCII(및 BIG5HKSCS) 인코딩으로 인식할 수 있습니다!
허용되는 문자를 개별적으로 나열하는 것이 좋습니다.
is_safe() case $1 in
*[!-_.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]*) false;;
esac
또한 따옴표로 묶어야 하는 빈 문자열에 유의하세요( ''
모든 일반 쉘에서 지원됨). 그리고 -
일부 도구가 옵션일 수 있다는 주장에 주의하세요.