使用 $SSH_ORIGINAL_COMMAND 只允许少数经过审查的命令的安全性

信息安全 SSH 重击
2021-08-29 13:11:41

使用authorized_keys带有 ssh 和包装脚本的强制命令,如下所示:

#!/usr/bin/env bash

case "$SSH_ORIGINAL_COMMAND" in
  /var/lib/authorized-scripts/*)
    $SSH_ORIGINAL_COMMAND
    ;;
  *)
    exit 1
    ;;
esac

恶意用户能否以某种方式链接另一个命令/usr/bin/authorized-scripts/,从而克服此安全措施,或者这是否安全?

表明我可以简单地使用ssh user@host '/var/lib/authorized-scripts/script.sh && cat /etc/passwd',但这在我的测试中不起作用。

我能否以某种方式提高此脚本的安全性,同时仍然允许使用用户提供的参数为单个 ssh 密钥执行多个命令?

我知道允许的命令本身当然不应该允许任何类型的子shell(find例如,由于它的功能,例如是 nogo exec)。

2个回答

您的强制命令不安全。考虑:

ssh -l user your-server /var/lib/authorized-scripts/../../../bin/rm -rf /

命令名称以它开头,/var/lib/authorized-scripts/所以它是安全的,对吧?不!

你会想要更多这些方面的东西:

#!/bin/sh

set -- $SSH_ORIGINAL_COMMAND
case "$1" in
  /var/lib/authorized-scripts/*)
    ;;
  *)
    exit 1
esac

command="${1#/var/lib/authorized-scripts/}"
shift
case "$command" in
  */*)
    # Simplest is to reject anything with a slash...
    exit 1
  .*)
    # ...and anything starting with dot.
    # If you need to whitelist subdirectories of /var/lib/authorized-scripts
    # then you need much more sophisticated pathname parsing and care.
    exit 1
  *)
    ;;
esac

exec "/var/lib/authorized-scripts/$command" "$@"

至于像命令中嵌入的shell语法&&;那应该是安全的。正如您已经发现的那样,这些事情不会由您的解决方案中的 shell 解释,而是逐字传递给命令。

但是,将解释命令参数中的通配符。如果您想避免这种情况,set -f请将set -- $SSH_ORIGINAL_COMMAND.

确保授权脚本以安全的方式解释其参数。参数可以是允许 shell 注入的选项(就像find -exec那样)、文件名,包括符号链接(指向不同目录中的文件)等。

最后:#!/usr/bin/env bash没有必要。您的脚本不使用 bashisms,那么为什么不通过在 下运行来提高便携性/bin/sh呢?

[披露:我写了下面描述的 sshdo]

有一个名为 sshdo 的程序可以做到这一点。它控制哪些命令可以通过传入的 ssh 连接执行。可在以下位置下载:

http://raf.org/sshdo/ (read manual pages here)
https://github.com/raforg/sshdo/

它有一个训练模式来允许所有尝试的命令,以及一个 --learn 选项来生成永久允许学习命令所需的配置。然后可以关闭训练模式,并且不会执行任何其他命令。

它还有一个 --unlearn 选项来停止允许不再使用的命令,以便在需求随时间变化时保持严格的最低权限。

它对它允许的内容非常挑剔。它不允许带有任何参数的命令。只能允许完整的 shell 命令,因此它可能无法满足您的需求。

但它确实支持简单的模式来表示类似的命令,这些命令仅在命令行上出现的数字(例如序列号或日期/时间戳)中有所不同。

它就像 ssh 命令的防火墙或白名单控制。