当前位置: 首页 > news >正文

记录一次SSH和SFTP服务分离后文件上传权限问题

开门见山

因服务器安全需求,需要将ssh和sftp服务分离,并创建一个用户组sftpuser::sftp,根目录权限均正常。用户sftpuser仅能通过sftp访问服务器,不能通过ssh访问服务器。但是,ssh应用用户appuser::sftp通过sftp建立链接并put文件后发现权限为600,导致所属组应用权限不足,应该为660可读写。

原因是因为umask默认为002,所以需要调整umask,又因为sftptuser为sftp登录并不是ssh登录,所以这里修改/ect/profile或/ect/bashrc并不生效,所以需要修改对应的sftpd_config配置。

sftpd_config部分配置如下:

cat /etc/ssh/sftpd_config

# override default of no subsystems
#Subsystem	sftp	/usr/libexec/openssh/sftp-server
Subsystem sftp internal-sftp

# Example of overriding settings on a per-user basis
#Match User anoncvs
#	X11Forwarding no
#	AllowTcpForwarding no
#	PermitTTY no
#	ForceCommand cvs server

Match Group sftp
    ChrootDirectory /app/sftpFile
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

寻觅答案

尝试ChatGPT寻找答案,给出的是:
Subsystem sftp internal-sftp -u 0006
发现并不起作用,而且全站给出的基本都是这个答案。
研究了很长时间后,又问了DeepSeek给出的答案是:
ForceCommand internal-sftp -u 0006
这次正确了,sftpuser访问sftp上传的文件权限为660

答疑解惑

于是我又问了一下原因:

为什么在Subsystem sftp internal-sftp后面加 -u 0006 不起作用,反而在ForceCommand
internal-sftp -u 0006 起作用?

在 OpenSSH 的配置中,Subsystem sftp 和 Match 块中的 ForceCommand 对 -u 参数的处理方式不同,这是由 OpenSSH 的设计机制决定的。以下是具体原因和解决方案:

1. 根本原因分析

(1) Subsystem 指令的限制
语法规则:
Subsystem sftp 的完整语法是:
Subsystem sftp [args]
但 internal-sftp 是 OpenSSH 内置的 SFTP 实现,直接跟在 Subsystem 后的参数会被忽略(这是历史遗留设计)。

实际行为:
即使您配置:

Subsystem sftp internal-sftp -u 0006
OpenSSH 仍会忽略 -u 0006,仅启用 internal-sftp 的默认行为(通常 umask 077)。

(2) ForceCommand 的正确用法
设计意图:
ForceCommand 会覆盖用户登录后的默认 Shell,其参数会完整传递给目标命令(包括 internal-sftp)。

生效逻辑:

ForceCommand internal-sftp -u 0006
这里的 -u 0006 会直接传递给 internal-sftp 进程,因此能正确设置 umask。

2. 技术细节对比

配置位置 参数传递机制 是否支持 -u 参数
Subsystem 参数被 OpenSSH 主进程忽略 ❌
ForceCommand 参数完整传递给子进程 ✅

3. 其他注意事项

目录权限要求:
ChrootDirectory(如 /app/sftpFile)必须满足:

属主为 root。

权限为 755(drwxr-xr-x)。

不可被属主或属组写入(安全限制)。

总结

为什么 Subsystem 中 -u 无效:OpenSSH 的设计限制,参数被忽略。

为什么 ForceCommand 有效:参数直接传递给 SFTP 子进程。

最终方案:在 Match 块的 ForceCommand 中指定 -u 0006,这是官方推荐的做法

http://www.dtcms.com/a/122014.html

相关文章:

  • AI比人脑更强,因为被植入思维模型【52】福格行为模型
  • 0303hooks-react-仿低代码平台项目
  • OSPF的数据报文格式【复习篇】
  • 算法基础—二分算法
  • STM32 vs ESP32:如何选择最适合你的单片机?
  • 网络协议学习
  • PDFtk
  • 2025年3月全国青少年软件编程等级考试(Python六级)试卷及答案
  • 带无源位置反馈气动V型调节开关球阀的特点解析-耀圣
  • find指令中使用正则表达式
  • C++中STL学习(一)——向量、栈、堆、集合
  • PyQt6实例_A股财报数据维护工具_解说并数据与完整代码分享
  • ISP的过程
  • 用户注册(阿里云手机验证码)
  • CNN(卷积神经网络)
  • 共工新闻社与韩国新华报社达成合作
  • Python | 第十四章 | 基于模块开发-出租系统
  • 如何设置 JVM 内存参数(-Xms、-Xmx、-Xss 等)?
  • 文件的操作
  • 自然语言处理入门6——RNN生成文本
  • 揭开 MCP 的神秘面纱:标准化 AI 上下文管理的未来(下)
  • 永磁同步电机 | 分类 / 转子结构 / FOC 控制 / 电路分析
  • Android 中集成 Unity 工程的步骤
  • 点云处理常用的软件、开源库及数据集
  • 将jar包制作成deb一键安装包
  • 从 Excel 到你的表格应用:条件格式功能的嵌入实践指南
  • 【机密计算顶会解读】13:CAGE:通过 GPU 扩展补充 Arm CCA
  • 2025年3月全国青少年软件编程等级考试(Python五级)试卷及答案
  • 图解Java设计模式
  • 005.Gitlab CICD变量使用