ssh
rsh
通过使用密码文件中的用户外壳程序执行命令来遵循传统。
这意味着我们无需ssh
任何配置即可解决此问题。
如果您不希望用户具有外壳程序访问权限,则只需用脚本替换该用户的外壳程序即可。如果您看一下,/etc/passwd
将会看到有一个为每个用户分配一个shell命令解释器的字段。该脚本既用作交互式登录的外壳ssh user@host
,也用作命令的外壳ssh user@host command arg ...
。
这是一个例子。我创建了一个foo
其外壳为脚本的用户。脚本将打印消息,my arguments are:
然后打印其参数(每个参数都放在单独的行中和尖括号中)并终止。在日志情况下,没有参数。这是发生了什么:
webserver:~
foo@localhost's password:
Linux webserver [ snip ]
[ snip ]
my arguments are:
Connection to localhost closed.
如果用户尝试运行命令,则如下所示:
webserver:~
foo@localhost's password:
my arguments are:
<-c>
<cat /etc/passwd>
我们的“外壳”接收-c
样式调用,将整个命令作为一个参数,就像/bin/sh
接收它的方式一样。
如您所见,我们现在可以做的是进一步开发脚本,以便它可以识别使用-c
参数调用了脚本的情况,然后解析字符串(例如通过模式匹配)。可以通过递归调用将允许的那些字符串传递给真实的shell /bin/bash -c <string>
。拒绝案例可以打印一条错误消息并终止(包括-c
丢失的案例)。
您必须谨慎编写此代码。我建议只写肯定的比赛,只允许非常具体的事情,而不允许其他任何事情。
注意:如果是root
,仍然可以通过覆盖su
命令中的shell来登录此帐户,例如su -s /bin/bash foo
。(选择替代shell。)非root用户无法执行此操作。
这是一个示例脚本:限制用户仅使用ssh
来git
访问下的存储库/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"
当然,我们相信,这些混帐程序git-upload-pack
和git-receive-pack
不要有破洞或逃生舱,这将使用户对系统的访问。
这是这种限制方案所固有的。用户已通过身份验证,可以在某个安全域中执行代码,而我们正在限制将该域限制为子域。例如,如果您允许用户vim
在特定文件上运行命令以对其进行编辑,则该用户只需使用即可获得外壳程序:!sh[Enter]
。