基于Python Paramiko实现SCP服务器时exec请求失败问题求解
问题根源分析
- SCP协议底层依赖SSH的
exec请求实现,你当前编写的Server类仅实现了shell和pty请求的处理逻辑,没有重写check_channel_exec_request回调方法,Paramiko默认会拒绝所有未显式声明支持的exec请求,这是exec request failed on channel 0报错的直接原因。 - 现有代码存在冗余逻辑错误:身份验证通过后你主动发起了到本机22端口的新Transport连接,还直接调用
interactive.interactive_shell(chan)抢占了会话通道,导致后续exec请求根本无法被正常接收处理。
修复步骤
步骤1:给Server类添加exec请求处理方法
在Server类中新增如下方法,允许exec请求并存储接收的命令:
def check_channel_exec_request(self, channel, command): logging.info(f"Received exec request: {command.decode()}") # 存储命令到实例属性,方便后续业务逻辑调用 self.command = command self.event.set() return True
步骤2:删除冗余错误逻辑
完全删除以下三行无效代码,服务器不需要主动向自身发起SSH连接,也不需要提前抢占通道启动交互shell:
transport = paramiko.Transport(sock=("192.168.34.10", 22)) transport.connect(username="root", password="password") interactive.interactive_shell(chan)
步骤3:添加SCP协议处理逻辑
SCP的-t参数表示当前是服务器端接收文件的场景,你需要按照SCP协议规则完成交互,替换原有后续的shell处理逻辑为以下代码:
server.event.wait() # 优先处理exec类请求(含SCP) if hasattr(server, 'command'): cmd = server.command.decode() # 匹配SCP上传请求 if cmd.startswith('scp -t'): # 解析目标存储路径 target_path = cmd.split(' ')[-1] # 向客户端返回0字节表示就绪,可以开始传输 chan.sendall(b'\x00') # 读取文件元信息,格式为 C<权限> <文件大小> <文件名>\n header = chan.recv(1024).decode() if not header.startswith('C'): chan.sendall(b'\x01') chan.close() sys.exit(1) # 解析元信息字段 mode, size, filename = header[1:].strip().split(' ') size = int(size) # 确认收到元信息,通知客户端发送文件内容 chan.sendall(b'\x00') # 接收文件内容 file_content = b'' while len(file_content) < size: chunk = chan.recv(min(4096, size - len(file_content))) if not chunk: break file_content += chunk # 接收传输结束标记 chan.recv(1) # 返回传输成功 chan.sendall(b'\x00') # 存储文件到本地,生产环境需要补充路径遍历漏洞防护 save_path = os.path.join(dir_local, filename) with open(save_path, 'wb') as f: f.write(file_content) chan.close() sys.exit(0) # 原有shell处理逻辑保留,用于普通SSH登录场景 chan.send("Success Connect\r\n\r\n") f = chan.makefile("rU") while True: cmd = f.readline().strip("\r\n") myCmd = os.popen(cmd).read() print(myCmd)
额外注意事项
- 上述SCP处理为最简实现,生产环境使用需要补充路径遍历防护、大文件分片存储、异常错误码返回、权限校验等逻辑。
- 测试前请确认代码中定义的
dir_local路径存在,且运行进程对该路径有写入权限。 - 如果需要支持SCP下载功能(客户端从服务器拉取文件),还需要额外适配
scp -f开头的命令逻辑。
内容的提问来源于stack exchange,提问作者user10121466
相关产品推荐
相关产品推荐

