如何在登录后将SSH用户限制为一组预定义的命令?

Mar*_*cel 80 linux ssh shell

这是一个安全的想法.我们的员工可以访问Linux服务器上的一些命令,但不是全部.他们应该可以访问日志文件(less logfile)或启动不同的命令(shutdown.sh/ run.sh).

背景资料:

所有员工都使用相同的用户名访问服务器:我们的产品以"正常"用户权限运行,不需要"安装".只需在用户目录中解压缩并运行即可.我们管理了几个"安装"应用程序的服务器.在每台机器上都有一个用户johndoe.我们的员工有时需要在命令行上访问应用程序以访问和检查日志文件或手动重启应用程序.只有一些人才能拥有完整的命令行访问权限.

我们在服务器上使用ppk身份验证.

如果employee1只能访问日志文件而employee2也可以执行X等,这将是很好的...

解决方案: 作为解决方案,我将使用接受答案command中所述的选项.我将创建自己的小shell脚本,这将是可以为某些员工执行的唯一文件.该脚本将提供几个可以执行的命令,但没有其他命令.我将使用下列参数从为表示在这里:authorized_keys

command="/bin/myscript.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
ssh-dss AAAAB3....o9M9qz4xqGCqGXoJw= user@host
Run Code Online (Sandbox Code Playgroud)

这对我们来说足够安全.谢谢,社区!

HD.*_*HD. 65

您还可以将密钥限制为允许的命令(在authorized_keys文件中).

即用户不会通过ssh登录然后拥有一组受限制的命令,而只允许通过ssh执行这些命令(例如"ssh somehost bin/showlogfile")

  • 本文为使用authorized_keys文件的多个命令提供了一些选项:http://www.linuxjournal.com/article/8257 (12认同)
  • O'Reilly SSH书籍对如何执行此操作有一个很好的解释,包括通过设置查看SSH_ORIGINAL_COMMAND环境变量的脚本来允许多个命令.http://oreilly.com/catalog/sshtdg/chapter/ch08.html (10认同)
  • [此服务器故障回答](http://serverfault.com/a/407508/50874)有一个很好的提示,了解如何通过使用导出的SSH_ORIGINAL_COMMAND变量来允许多个命令. (5认同)
  • 有一个这样的例子就很好了 (2认同)

Kaz*_*Kaz 30

sshrsh通过使用密码文件中的用户shell程序来执行命令,从而遵循传统.

这意味着我们可以ssh在不涉及任何方式配置的情况下解决此问题.

如果您不希望用户能够访问shell,那么只需用脚本替换该用户的shell即可.如果您查看,/etc/passwd您将看到有一个字段为每个用户分配一个shell命令解释程序.该脚本既可用作交互式登录ssh user@host 以及命令的shell ssh user@host command arg ....

这是一个例子.我创建了一个fooshell是脚本的用户.该脚本打印消息my arguments are:后跟其参数(每个都在一个单独的行和尖括号中)并终止.在登录的情况下,没有参数.这是发生的事情:

webserver:~# ssh foo@localhost
foo@localhost's password:
Linux webserver [ snip ]
[ snip ]
my arguments are:
Connection to localhost closed.
Run Code Online (Sandbox Code Playgroud)

如果用户尝试运行命令,它看起来像这样:

webserver:~# ssh foo@localhost cat /etc/passwd
foo@localhost's password:
my arguments are:
<-c>
<cat /etc/passwd>
Run Code Online (Sandbox Code Playgroud)

我们的"shell"接收一个-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 )
    ;; # continue execution
  ( * )
    printf "command not allowed\n"
    exit 1
    ;;
esac

# Canonicalize the path name: we don't want escape out of
# git via ../ path components.

gitpath=$(readlink -f "$2")  # GNU Coreutils specific

case "$gitpath" in
  ( /git/* )
     ;; # continue execution
  ( * )
    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"
Run Code Online (Sandbox Code Playgroud)

当然,我们相信这些Git程序git-upload-pack并且git-receive-pack没有漏洞或逃生舱口,可以让用户访问系统.

这是这种限制方案所固有的.用户通过身份验证以执行某个安全域中的代码,我们正在限制将该域限制为子域.例如,如果您允许用户vim在特定文件上运行命令进行编辑,则用户可以使用:!sh[Enter].

  • 说真的,这是非常危险的.是什么阻止我执行`git-receive-pack'/ git /'; dd if =/dev/urandom of =/dev/sda`? (4认同)

Vin*_*vic 14

您正在寻找的是Restricted Shell.Bash提供了这样一种模式,用户只能执行其主目录中存在的命令(并且它们不能移动到其他目录),这对您来说可能已经足够了.

我发现这个帖子非常具有说明性,如果有点过时了.

  • @Ubersoldat:请在所有帖子中长大并降低攻击性.他在问这个限制是否仅适用于bash或子进程(并回答他的问题,事实证明它没有). (3认同)
  • 我收回这一点,bash _will_ 在 sshd 下以非交互方式运行时调用 .bashrc(不是 .profile);但是,您必须确保显式设置 PATH 并禁用 .bashrc 中的内置函数和别名 - 更改为不在 PATH 或 .ssh/ 或 .bashrc 中/上方的子目录也是一个好主意。任何可以写入任意文件的命令都会产生问题 - 这些并不总是显而易见的,例如 sed 'w' 命令可用于覆盖 .bashrc 并中断。如果您可以使用 chroot jail,则它总是更安全,并且 ssh 强制命令将受到更多限制。 (2认同)

Tho*_*mas 6

GNU Rush可能是实现这一目标的最灵活、最安全的方法:

GNU Rush 是一个受限用户 Shell,专为提供对其资源(例如 svn 或 git 存储库、scp 等)的有限远程访问的站点而设计。使用复杂的配置文件,GNU Rush 使您可以完全控制用户执行的命令行以及系统资源的使用,例如虚拟内存、CPU 时间等。


Yet*_*eti 5

你为什么不编写自己的登录外壳?为此使用 Bash 会非常简单,但您可以使用任何语言。

Bash 中的示例

使用您最喜欢的编辑器创建文件/root/rbash.sh(这可以是任何名称或路径,但应该是chown root:rootchmod 700):

#!/bin/bash

commands=("man" "pwd" "ls" "whoami")
timestamp(){ date +'%Y-%m-%s %H:%M:%S'; }
log(){ echo -e "$(timestamp)\t$1\t$(whoami)\t$2" > /var/log/rbash.log; }
trycmd()
{
    # Provide an option to exit the shell
    if [[ "$ln" == "exit" ]] || [[ "$ln" == "q" ]]
    then
        exit
        
    # You can do exact string matching for some alias:
    elif [[ "$ln" == "help" ]]
    then
        echo "Type exit or q to quit."
        echo "Commands you can use:"
        echo "  help"
        echo "  echo"
        echo "${commands[@]}" | tr ' ' '\n' | awk '{print "  " $0}'
    
    # You can use custom regular expression matching:
    elif [[ "$ln" =~ ^echo\ .*$ ]]
    then
        ln="${ln:5}"
        echo "$ln" # Beware, these double quotes are important to prevent malicious injection
        
        # For example, optionally you can log this command
        log COMMAND "echo $ln"
    
    # Or you could even check an array of commands:
    else
        ok=false
        for cmd in "${commands[@]}"
        do
            if [[ "$cmd" == "$ln" ]]
            then
                ok=true
            fi
        done
        if $ok
        then
            $ln
        else
            log DENIED "$cmd"
        fi
    fi
}

# Optionally show a friendly welcome-message with instructions since it is a custom shell
echo "$(timestamp) Welcome, $(whoami). Type 'help' for information."

# Optionally log the login
log LOGIN "$@"

# Optionally log the logout
trap "trap=\"\";log LOGOUT;exit" EXIT

# Optionally check for '-c custom_command' arguments passed directly to shell
# Then you can also use ssh user@host custom_command, which will execute /root/rbash.sh
if [[ "$1" == "-c" ]]
then
    shift
    trycmd "$@"
else
    while echo -n "> " && read ln
    do
        trycmd "$ln"
    done
fi
Run Code Online (Sandbox Code Playgroud)

您所要做的就是将此可执行文件设置为您的登录 shell。例如,编辑您的/etc/passwd文件,并将该用户当前的登录 shell 替换/bin/bash/root/rbash.sh.

这只是一个简单的示例,但您可以根据需要将其设置为高级,想法就在那里。小心不要通过更改您自己和唯一用户的登录外壳来锁定自己。并且总是测试奇怪的符号和命令,看看它是否真的安全。

您可以使用以下命令对其进行测试:su -s /root/rbash.sh

当心,确保匹配整个命令,并小心通配符!更好地排除猛砸符号,例如;&&&||$,和反引号以确保万无一失。

根据您给予用户的自由,它不会比这更安全。我发现通常我只需要让用户只能访问几个相关命令,在这种情况下,这确实是更好的解决方案。但是,您是否希望给予更多自由,监狱和权限可能更合适。错误很容易犯,只有在为时已晚时才会注意到。

  • @Farzan 您可以在变量中执行命令,例如 `ln="service httpd restart"`,使用:`${ln[@]}`。仍然一定要考虑安全问题,在这种情况下,仅包含字母数字字符和空格的白名单会很有用。但你也可以这样做:`if [[ "$ln" == "restart-httpd"];then service httpd restart;fi`,并使用类似的简单命令。 (2认同)