关于程序调用普通用户ssh执行shell命令和sftp问题总结
调用root是没有相关问题,普通用户存在一定问题
保证后端服务器执行ssh user@IP
和 sftp user@IP
是没有问题的
执行sftp user@IP
报错:Connection closed
ssh -v user@ip
可以输出调试日志
1. 首先排查用户密码是否过期
chage -l 用户名
Last password change : Mar 22, 2025
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 7
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
Password expires : never 用不过期
排除这个问题
- 如果过期了 执行
chage -M 99999 用户名
2. 查看/etc/passwd/
文件是否正确
cat /etc/passwd
是否存在此用户
nginx:x:1000:1000::/home/nginx:/bin/bash
应当以/bin/bash结尾 如果是/bin/flase
则不支持交互式ssh,这个和非交互式调用关系不大,主要是检查配置是否有问题
3. 查看SFTP
的子进程是否有权限
查看这个的权限
ls -al /usr/libexec/openssh/sftp-server
检查是否有其他用户可执行的权限,-rwxr - xr - x 比如这样是文件所有者和所属组和其他用户,其他用户应当由x可执行的权限
如果没有执行chmod 755 /usr/libexec/openssh/sftp-server
/usr/libexec/openssh/sftp-server
是openssh协议中一个很重要的组件
以上都没有解决问题
4. 添加配置参数,ssh和sftp的配置文件是/etc/ssh/sshd_config
文件中找到下面这个配置,是sftp的配置
Subsystem sftp /usr/libexec/openssh/sftp-server
# Example of overriding settings on a per-user basis
# Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
默认其他用户只能sftp到/home/用户/下才有权限,然后通过xftp等软件好像是会调用到服务器本身sftp的子进程,而服务器本身用sftp普通用户无法调用到目标服务器的子进程造成无法建立sftp连接,这个是报错出现的原因
通过拼凑资料加上自我理解得出的结论
- 解决方法添加配置
Match User nginx #跟普通用户
ChrootDirectory none
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
ChrootDirectory none 这个是调整普通用户可sftp的目录的,这样设置为无限制,若限制可后跟限制的目录
ForceCommand internal-sftp 强制使用sftp
AllowTcpForwarding no 不允许tcp进行转发,例如一些tcp端口的服务
X11Forwarding no 不允许图形界面转发
配置后可以使用sftp了,但是ssh无法使用了。
去掉ForceCommand internal-sftp
又回到原来的样子
5. 解决ssh和sftp无法同时使用问题
修改/etc/ssh/sshd_config
配置
#需要注释掉下方这个,问题就出来他
#Subsystem sftp /usr/libexec/openssh/sftp-server
改成下方配置
Subsystem sftp internal-sftp
Match User nginx
ChrootDirectory none
AllowTcpForwarding no
X11Forwarding no
- 重启ssh服务
systemctl restart ssh
解决。
6. 结论
-
思路应当是先找日志,通过日志分析,是建立了ssh连接,但是在尝试建立sftp连接的时候出现了未知错误,连接关闭
-
熟悉sftp建立机理,建立连接时,先建立ssh连接,然后建立sftp连接,会用到sftp的一个子进程,即
Subsystem sftp /usr/libexec/openssh/sftp-server
这个东西 -
下一步应当找无法建立sftp连接的原因,如果密码过期,ssh是都建立不了连接的,因为sftp是基于ssh的
-
然后分析原因,很有可能是权限问题,或者openssh协议兼容性的问题
-
Subsystem sftp /usr/libexec/openssh/sftp-server
是一个独立的一个可执行进程,Subsystem sftp internal-sftp
是内置集成到openssh协议里面的,他俩作用一样,但是前者兼容性好,后者不占用资源。然后我查看了前者的权限,其他用户是有可执行的权限的,所以我猜测可能是普通用户用本地sftp的时候无法调用sftp的子进程。 -
举一反三,如果想禁用ssh协议,而只允许sftp协议,就可以禁用掉这个sftp子进程,也不添加使用那个内置的子进程,并配置强制sftp就可以。