SFTP 上传提示 Permission Denied 怎么办?目录权限、属主与 SSH 限制排查

2026-09-20

直接答案:SFTP 能登录但上传 Permission denied,说明认证通常已完成,失败发生在远端路径或策略。先在 SFTP 中确认当前目录与目标文件名,再在服务器检查该用户的 UID/组、目标目录每一级搜索权限、目录写权限、已有同名文件属主、ACL、只读挂载和磁盘状态。若使用 ChrootDirectory,chroot 根目录按 OpenSSH 要求必须由 root 拥有且不能被其他用户写,真正可上传的目录应建立在其下并授予目标用户,而不是把 chroot 根改成 777。

本文处理认证成功后上传、改名、删除或创建目录失败。若连接阶段显示 Permission denied (publickey,password),那是 SSH 身份认证问题,应查密钥、账号和 sshd 配置;两个“Permission denied”所处阶段完全不同。

本文按 2026 年 9 月可查的官方文档核对。示例命令以只读取证为主;凡涉及删除、覆盖、重启、权限、网络或数据库参数的动作,都应先确认操作对象、备份、维护窗口和带外恢复入口。不同发行版与软件版本的路径可能不同,必须先查询实际配置再改。

先用证据判断故障在哪一层

现象或检查点 它能说明什么 直接证据 不要误判为
登录即被拒绝 认证、AllowUsers或密钥问题 客户端-vvv与auth日志 上传目录权限
可列目录但不能上传 目录缺写/搜索权限或只读挂载 namei、id、findmnt与ACL 网络端口
新文件可传、覆盖旧文件失败 旧文件属主、模式或原子改名目录权限 stat目标与临时文件 账号配额
chroot配置后无法进入 路径组件所有权不符合OpenSSH要求 sshd日志与ChrootDirectory链 用户home不存在
仅面板/应用目录失败 部署用户与Web用户边界不同 UID/GID、ACL和发布流程 SFTP协议故障

这张表的用法不是“看到一个关键词就改一个参数”,而是把客户端、DNS或边缘、Web 代理、应用、数据层依次分开。至少保留故障时间、完整 URL、状态码、关键响应头、同一时刻的服务日志和一份正常样本。只有时间能够对齐,才能判断两个现象是否属于同一次故障。

六步排查与修复顺序

1. 区分认证失败和文件操作失败

保存客户端完整错误与时间,确认是否已经看到远端目录。服务端查 sshd/auth journal:认证失败要处理密钥或账号;认证成功后某个 put 失败才进入目录权限分析。

2. 确认远端真实路径与用户身份

SFTP chroot 后看到的 / 可能不是宿主根目录。记录 pwd、目标路径和登录用户名,在服务端用 id 确认 UID、主组和附加组;不要凭面板显示名猜测实际身份。

3. 检查路径每一级与挂载状态

用 namei -l 检查父目录搜索权限,getfacl 查看 ACL,findmnt -T 确认不是只读挂载。创建文件需要目录写与搜索权限;覆盖、删除和改名主要受父目录权限影响,不只是目标文件本身。

4. 核对 Chroot 与 Match 规则

阅读 sshd -T/配置中的 Match、ForceCommand、internal-sftp、ChrootDirectory 和 umask。chroot 路径组件必须 root 所有且不可被组/其他用户写;在其下创建如 upload 的可写子目录。

5. 设计部署与Web用户协作

不要让所有用户共享 777。可用专用部署组、setgid 目录或精确 ACL,让 SFTP 用户写入发布区,再由受控流程部署到 Web 根;上传目录应禁止执行脚本并与配置、密钥分离。

6. 用最小文件完成正反例验收

以目标账号上传、改名、覆盖和删除一个无敏感测试文件,再验证不应访问的父目录和配置文件仍被拒绝。检查新文件属主、组和 umask,确认 Web 进程只获得需要的读/写能力。

可复制的只读取证命令

以下命令中的域名、服务名、路径和时间范围要替换为自己的真实值。先执行查询命令并保存原始输出;不要把“命令能运行”误当成“业务已恢复”。

text id sftpuser namei -l /srv/sftp/client/upload getfacl -p /srv/sftp/client/upload findmnt -T /srv/sftp/client/upload -o TARGET,SOURCE,FSTYPE,OPTIONS sshd -T | grep -Ei 'subsystem|chrootdirectory|forcecommand|allowusers|allowgroups'

  • id sftpuser:查看目标账号UID、主组和附加组
  • namei -l /srv/sftp/client/upload:逐级检查真实宿主路径权限与所有者
  • getfacl -p /srv/sftp/client/upload:查看传统模式位之外的ACL
  • findmnt -T /srv/sftp/client/upload -o TARGET,SOURCE,FSTYPE,OPTIONS:确认挂载点不是只读且映射符合预期
  • sshd -T | grep -Ei 'subsystem|chrootdirectory|forcecommand|allowusers|allowgroups':读取全局有效配置;Match条件需用-C按目标连接展开

如命令输出包含公网 IP、用户名、Cookie、令牌、数据库连接串或客户数据,分享工单前先脱敏。对比时保留时间戳、时区和命令本身,否则后来无法复现同一观察条件。

五个最容易扩大故障的误区

  • chmod -R 777:破坏隔离并让Web目录可被任意本地用户写,仍可能无法满足chroot要求。
  • 把 chroot 根目录交给上传用户:OpenSSH 会因路径不安全拒绝会话。
  • 只改目标文件不看父目录:创建、删除和改名主要需要目录权限。
  • 把Web服务用户直接设为root:为解决上传方便扩大整个应用权限,风险远超问题本身。
  • 忘记ACL和只读挂载:模式位看似正确时,额外策略仍可能拒绝写入。

变更、回滚与数据边界

修改前保存 stat、getfacl、sshd配置和 sshd -T 输出。若权限调整让用户越权访问、Web目录可执行上传或 chroot 失效,立即恢复原属主/模式/ACL 和配置并 reload sshd;保持现有管理会话与控制台入口。不要递归覆盖整个站点权限,回滚应针对准确路径。

如果只能先恢复服务、还不能确认根因,应把措施标记为“临时缓解”,例如限流、摘除单节点、切回上一配置或临时绕过一层代理。恢复后仍要在受控环境复现原因,并验证同类故障不会在下一次重启、发布或高峰重新出现。

统一验收清单

  • [ ] 已区分认证与文件操作阶段
  • [ ] 登录用户UID/GID明确
  • [ ] 远端路径映射到真实宿主路径
  • [ ] 父目录搜索与目标目录写权限正确
  • [ ] 挂载为预期读写状态
  • [ ] ChrootDirectory满足root所有和不可写要求
  • [ ] 上传文件属主、组与umask正确
  • [ ] 敏感目录和脚本执行仍被拒绝

验收必须同时覆盖机器内部和真实外部路径。首页返回 200 不能证明上传、长连接、登录、数据库写入或移动端都正常;同样,控制台显示“运行中”也不能证明应用已能处理请求。至少选一个正常请求、一个边界请求和一个失败请求,记录预期与实际结果。

相关内容与隔离测试入口

建议先阅读SSH连接不上、Linux安全加固、服务器日志保留,把本问题放回完整请求链路。若生产环境不适合直接试验,可查看美国轻量云的当前规格与库存,搭建与生产隔离的复现环境;测试机不能替代生产备份,价格、库存和可选配置以实时产品页为准。

常见问题

能登录为什么还提示 Permission denied?

认证只证明身份可建立会话,写文件还需要目标目录、挂载、ACL和策略允许。

为什么 chroot 根不能给用户写?

OpenSSH 为防止用户篡改隔离环境,要求 ChrootDirectory 路径组件由 root 拥有且不可被组或其他用户写。

覆盖文件需要文件写权限还是目录写权限?

取决于客户端策略。直接截断需要文件写权限,先传临时文件再原子改名还需要目录写权限;应看服务端操作日志。

SFTP 和 FTP 权限一样吗?

底层Unix文件权限相同部分可复用,但认证、chroot和服务配置不同,不能用FTP面板设置推断SFTP。

如何让SFTP用户上传但网站只读?

使用专用上传目录和部署流程,或精确组/ACL;Web根由部署用户管理,Web进程仅读,上传目录禁止脚本执行。

官方参考资料

最近更新