ssh
postępuje zgodnie z rsh
tradycją, używając programu powłoki użytkownika z pliku haseł do wykonywania poleceń.
Oznacza to, że możemy rozwiązać ten problem bez angażowania ssh
w jakikolwiek sposób konfiguracji.
Jeśli nie chcesz, aby użytkownik miał dostęp do powłoki, po prostu zastąp powłokę tego użytkownika skryptem. Jeśli /etc/passwd
zajrzysz do środka, zobaczysz, że istnieje pole, które przypisuje każdemu użytkownikowi interpreter poleceń powłoki. Skrypt jest używany jako powłoka zarówno do ich interaktywnego logowania, ssh user@host
jak i do poleceń ssh user@host command arg ...
.
Oto przykład. Stworzyłem użytkownika, foo
którego powłoką jest skrypt. Skrypt wypisuje komunikat, my arguments are:
po którym następują jego argumenty (każdy w osobnym wierszu i w nawiasach ostrych) i kończy. W przypadku dziennika nie ma argumentów. Oto, co się dzieje:
webserver:~
foo@localhost's password:
Linux webserver [ snip ]
[ snip ]
my arguments are:
Connection to localhost closed.
Jeśli użytkownik spróbuje uruchomić polecenie, wygląda to tak:
webserver:~
foo@localhost's password:
my arguments are:
<-c>
<cat /etc/passwd>
Nasza „powłoka” otrzymuje -c
wywołanie stylu, z całym poleceniem jako jednym argumentem, dokładnie w taki sam sposób, w /bin/sh
jaki je otrzyma.
Jak widać, możemy teraz dalej rozwijać skrypt, tak aby rozpoznawał przypadek, gdy został wywołany z -c
argumentem, a następnie analizuje ciąg (powiedzmy przez dopasowanie do wzorca). Te ciągi, które są dozwolone, mogą być przekazane do prawdziwej powłoki przez rekurencyjne wywołanie /bin/bash -c <string>
. Przypadek odrzucenia może wydrukować komunikat o błędzie i zakończyć (w tym przypadek, gdy go -c
brakuje).
Musisz uważać, jak to piszesz. Polecam pisać tylko pozytywne dopasowania, które pozwalają tylko na bardzo konkretne rzeczy i nie pozwalają na wszystko inne.
Uwaga: jeśli tak root
, nadal możesz zalogować się na to konto, zastępując powłokę w su
poleceniu, w ten sposób su -s /bin/bash foo
. (Wybrana powłoka zastępcza). Nie-root nie może tego zrobić.
Oto przykładowy skrypt: ogranicz użytkownika do korzystania tylko ssh
z git
dostępu do repozytoriów w ramach /git
.
#!/bin/sh
if [ $# -ne 2 ] || [ "$1" != "-c" ] ; then
printf "interactive login not permitted\n"
exit 1
fi
set -- $2
if [ $# != 2 ] ; then
printf "wrong number of arguments\n"
exit 1
fi
case "$1" in
( git-upload-pack | git-receive-pack )
;;
( * )
printf "command not allowed\n"
exit 1
;;
esac
gitpath=$(readlink -f "$2")
case "$gitpath" in
( /git/* )
;;
( * )
printf "access denied outside of /git\n"
exit 1
;;
esac
if ! [ -e "$gitpath" ] ; then
printf "that git repo doesn't exist\n"
exit 1
fi
"$1" "$gitpath"
Oczywiście ufamy, że te programy Git git-upload-pack
i git-receive-pack
nie mają dziur ani włazów, które umożliwią użytkownikom dostęp do systemu.
Jest to nieodłączne w tego rodzaju schemacie ograniczeń. Użytkownik jest uwierzytelniany w celu wykonania kodu w określonej domenie bezpieczeństwa, a my wzywamy do ograniczenia tej domeny do subdomeny. Na przykład, jeśli pozwolisz użytkownikowi uruchomić vim
polecenie na określonym pliku w celu jego edycji, użytkownik może po prostu uzyskać powłokę za pomocą :!sh[Enter]
.