安德魯克建议反向连接以便与其他人建立轻松的 SSH 连接(用于远程帮助)。要实现这一点,需要有其他用户接受连接。该用户需要能够通过服务器转发其端口(服务器充当代理)。
我如何创建一个只能执行上述操作的受限用户?
新用户必须不是能够:
- 执行shell命令
- 访问文件或上传文件到服务器
- 使用服务器作为代理(例如 webproxy)
- 访问因防火墙而无法公开访问的本地服务
- 终止服务器
总而言之,我如何创建一个受限的 SSH 用户,该用户只能在没有权限的情况下连接到 SSH 服务器,以便我可以通过该连接与他的计算机进行连接?
答案1
TL;DR - 转到答案底部,“应用限制”
添加受限用户包括两部分:1. 创建用户 2. 配置 SSH 守护进程 (sshd)
配置 sshd
了解 SSH 可能性的最佳途径是阅读相关的手册页:
SSH 客户端可以在哪里执行操作?
在限制某些操作之前,您需要了解 SSH 的功能。查阅手册页可得出以下结论:
- Shell 命令执行
- 通过 sftp 上传文件
- 转发端口
- 客户端将(未)使用的端口转发到服务器
- 服务器将其端口转发给客户端
- 服务器将另一台主机的端口转发给客户端(代理)
- X11转发(显示转发)
- 身份验证代理转发
- 隧道设备的转发
来自验证部分sshd(8) 手册页:
如果客户端成功验证身份,则会进入准备会话的对话框。此时客户端可能会请求以下内容 分配伪 tty、转发 X11 连接、转发 TCP 连接或转发身份验证代理连接通过安全通道。
此后,客户端可以请求 shell 或执行命令. 双方随后进入会话模式。在此模式下,任何一方都可以随时发送数据,这些数据在服务器端的 shell 或命令与客户端的用户终端之间进行转发。
限制 SSH 功能的选项
改变行为的文件及其选项包括:
~/.ssh/authorized_keys
- 包含允许连接的键,可以提供选项:command="command"
- 忽略用户提供的命令(如果有)。请注意,客户端可以指定 TCP 和/或 X11 转发,除非明确禁止. 注意此选项适用于 shell、命令或子系统的执行。no-agent-forwarding
- 当此密钥用于身份验证时,禁止身份验证代理转发。no-port-forwarding
- 当此密钥用于身份验证时禁止 TCP 转发no-X11-forwarding
- “当此密钥用于身份验证时禁止 X11 转发。”permitopen="host:port"
- 限制本地“ssh -L”端口转发,使得它只能连接到指定的主机和端口。
~/.ssh/environment
- 此文件在登录时被读入环境(如果存在)。环境处理默认被禁用,并通过 PermitUserEnvironment 选项进行控制~/.ssh/rc
- 包含在用户主目录可访问之前运行的初始化例程。/etc/ssh/sshd_config
- 系统范围的配置文件AllowAgentForwarding
- 指定是否允许 ssh-agent(1) 转发。AllowTcpForwarding
ForceCommand
- “强制执行 ForceCommand 指定的命令,忽略客户端提供的任何命令以及 ~/.ssh/rc(如果存在)。使用带有 -c 选项的用户登录 shell 调用该命令。”GatewayPorts
- “指定是否允许远程主机连接到为客户端转发的端口。默认情况下,sshd(8) 将远程端口转发绑定到环回地址。这可以防止其他远程主机连接到转发端口。GatewayPorts 可用于指定 sshd 应允许远程端口转发绑定到非环回地址,从而允许其他主机连接。”PermitOpen
:指定允许 TCP 端口转发的目标。转发规范必须采用以下形式之一:
PermitOpen host:port PermitOpen IPv4_addr:port PermitOpen [IPv6_addr]:port
可以通过用空格分隔来指定多个转发。可以使用“any”参数来删除所有限制并允许任何转发请求。默认情况下,所有端口转发请求均被允许。
PermitTunnel
- 指定是否允许 tun(4) 设备转发。默认为“否”X11Forwarding
- 指定是否允许 X11 转发。默认为“否”
应用限制
修改系统范围的配置文件/etc/ssh/sshd_config
允许即使应用了基于密码的身份验证或~/.ssh/authorized_keys
意外删除了限制,配置仍可应用。如果您修改了全局默认值,则应取消注释相应的选项。
Match User limited-user
#AllowTcpForwarding yes
#X11Forwarding no
#PermitTunnel no
#GatewayPorts no
AllowAgentForwarding no
PermitOpen localhost:62222
ForceCommand echo 'This account can only be used for [reason]'
现在添加一个用户:
sudo useradd -m limited-user
ForceCommand
如果将 shell 设置为非 shell,则可以省略该选项,如/bin/false
(或/bin/true
)/bin/false -c [command]
不会执行任何操作。
现在客户端只能通过 SSH 连接到服务器环回地址上的端口 62222(它不会监听公共 IP 地址)
禁用AllowTcpForwarding
还会禁止使用-R
,从而使这种受限帐户无法用于转发单个端口。PermitOpen localhost:62222
假定服务器上的端口 62222 从未使用过,因为客户端可以愉快地连接到该端口并对其进行监听。
如果系统范围配置中允许 TCP 转发并禁用基于密码的身份验证,您也可以使用每个密钥设置。~/.ssh/authorized_keys
在 之前编辑并添加以下选项ssh-
(选项 和 之间有一个空格ssh-
):
command="echo 'This account can only be used for [reason]'",no-agent-forwarding,no-X11-forwarding,permitopen="localhost:62222"
核实
为了确保它按预期工作,需要运行一些测试用例。在下面的命令中,host
如果未在中设置,则应将其替换为实际登录名~/.ssh/config
。在命令后面,显示了应在客户端或服务器上执行的命令(如指定)。
# connection closed:
ssh host
# connection closed (/bin/date is not executed):
ssh host /bin/date
# administratively prohibited (2x):
ssh host -N -D 62222 # client: curl -I --socks5 localhost:62222 example.com
ssh host -N -L 8080:example.com:80 # client: curl -I localhost:8080
sftp host
# should be possible because the client should forward his SSH server
ssh host -N -R 8080:example.com:80 # server: curl -I localhost:8080
# This works, it forwards the client SSH to the server
ssh host -N -R 62222:localhost:22
# unfortunately, the client can listen on that port too. Not a big issue
ssh host -N -L 1234:localhost:62222
结论
检查表:SSH 用户不应该能够:
- 执行 shell 命令 -完毕
- 访问文件或将文件上传到服务器 -完毕
- 使用服务器作为代理(例如 webproxy) -完毕
- 访问因防火墙而无法公开访问的本地服务 -部分,客户端无法访问除62222之外的其他端口,但可以监听并连接服务器端的62222端口
- 终止服务器 –完毕 (请注意,这些检查仅限于 SSH 服务器。如果您的机器上有其他易受攻击的服务,则可能允许攻击者运行命令、杀死服务器等。)
答案2
我确信有很多解决方案可以解决这个问题,而且有很多比我建议的解决方案更强大。但是,这可能足以满足您的需求。为了做到这一点,我假设用户能够进行基于 ssh 密钥的身份验证(putty 或任何 unix ssh 都应该支持这一点)。
像平常一样添加用户(“adduser”或任何其他工具)
创建用户 .ssh 目录和 .ssh/authorized_keys
your_user $ sudo -Hu ssh_forwarder /bin/bash
ssh_forwarder $ cd ~
ssh_forwarder $ mkdir .ssh
ssh_forwarder $ ( umask 066 && cat > .ssh/authorized_keys ) <<EOF
no-agent-forwarding,no-X11-forwarding,command="read a; exit" ssh-rsa AAAB3NzaC1y....2cD/VN3NtHw== smoser@brickies
EOF
- 禁用该帐户的密码访问。
your_user $ sudo usermod --lock ssh_forwarder
现在,用户进入您的系统的唯一方法是通过访问正确的 ssh 密钥,并且无论他们尝试运行什么,ssh 都会为他们运行“/bin/bash -c 'read a'”。'read a' 将简单地读取直到换行符,然后 shell 将退出,因此用户只需按'enter'即可终止连接。
您还可以在“command=”中执行许多其他操作。查看man authorized_keys
并搜索“command”以获取更多信息。
如果您不喜欢按回车键终止连接,您可以对“command=”条目使用类似下面的内容:
command="f=./.fifo.$$ && mkfifo $f && trap \"rm -f $f\" EXIT && read a <$f && echo $a; exit;"
这只会在用户主目录中创建一个临时 fifo,然后尝试从中读取。不会有任何内容写入该文件,因此这将无限期挂起。此外,如果您想强制终止该连接,您可以执行以下操作:
your_user$ echo GOODBYE | sudo tee ~ssh_forwarder/.fifo.*
这应该会使用很少的资源,并且脚本中不应该出现任何错误而导致 shell 终止。
sleep 1h; echo You have been here too long. Good bye.
我暂时还不知道如何允许用户远程转发 ( ssh -R
) 但限制 ( ssh -L
)。也许可以使用“permitopen”。 谷歌搜索没什么帮助。似乎可以使用类似“no-port-forwarding,permitremoteopen=10001”这样的命令来允许ssh -R 6901:localhost:6901
。
这是A解决方案。它绝对可以改进,任何远程端口的打开都应该受到严格审查。如果我的目标是允许我的祖母连接到我的局域网,这样我就可以使用 vnc 查看她的屏幕,并且只有她才能访问这些密钥,我个人会觉得相当安全。如果这是针对企业,则需要进行更彻底的调查。需要注意的一件事是ssh -N
根本不请求 shell,因此“command=”代码不会执行。
其他可能更安全的机制可能包括为用户创建自定义 shell,甚至使用 apparmour 将其锁定。
答案3
尝试command="exit"
这将强制用户使用此命令进行端口转发
ssh -NfR EXTERNAL_PORT:localhost:INTERNAL_PORT usr@server -i key