【发布时间】:2015-08-07 02:51:41
【问题描述】:
短版:
- Paramiko 在大容量数据期间有一个known issue rekeying 转让
- 引用的补丁(现在是 dist 的一部分)通过调整时间来缓解它,但是对于大容量传输,如果在更新密钥完成之前有太多数据流,仍然有可能中止连接
- 我看到的最简单的解决方法是引用
paramiko.Packetizer.need_rekey(),如果它返回 True,则在我的数据传输线程中阻塞或休眠
我的问题:
- 当我拥有的是
paramiko.SSHClient()对象时如何访问paramiko.Packetizer.need_rekey()的任何参考或示例? - 有解决此问题的更好建议吗?
加长版:
现代 SSH 会话需要在一定时间或数据通过后重新加密。如果没有足够快地响应重新生成密钥的请求 - 其中“足够快”意味着自请求重新生成密钥以来经过了太多时间或太多数据 - 连接将作为安全保护机制中止。
Paramiko 过去在重新生成密钥请求和重新生成密钥之间有 20 个数据包的非常狭窄的限制。 This patch 2012 年
增加(d) re-key request & 之间接收数据包的限制 完成从 20 包到 2**29 包。
在我的应用程序中,我使用paramiko.transport.open_channel 通过转发端口传输大型(10-30 GB)数据流。如果我在同一个 LAN 上的两台主机之间执行此操作,它会 100% 成功。如果主机位于不同的 LAN 上,并且延迟越来越高,它就会开始出现故障 - 比如说 50% 的时间,但可能不止于此。
不用说,将 25 GB 的 SSH 连接丢失为 30 GB 的数据传输可能会令人沮丧。
使用 OpenSSH 作为客户端,我没有这个问题,这与我读过的报告一致,即重新加密互操作性存在问题。据报道,OpenSSH 可以与 自身 无缝地重新生成密钥;与其他人...不太一样。但是我已经在使用 Paramiko 登录远程主机并运行必要的命令来启动数据传输;必须打开一个单独的 OpenSSH 会话来转发数据的端口是很麻烦的。
正确的解决方法似乎是 Paramiko 应该阻止或延迟未更新密钥的数据包,同时它会重新加密 - 这似乎是 OpenSSH 处理它的方式,尽管我还没有看到权威的确认。但这可能是一个雄心勃勃的变化,会影响很多人并且需要时间。
作为临时措施,简单的解决方法是让我的脚本自行调节。我很乐意插入sleep 呼叫或完全阻止数据传输,同时处理重新输入密钥。如果没有在后台进行大量数据传输,密钥更新应该很容易在最后期限内完成。
Paramiko 提供了一种查看是否已请求更新密钥的方法 - paramiko.Packetizer.need_rekey()。但我不知道如何在我现有的 SSHClient() 对象的上下文中调用它。对于paramiko.transport.* 方法,我可以使用paramiko.SSHClient().get_transport() 创建一个用于调用它们的对象。似乎没有 paramiko.SSHClient().get_packetizer() 等效项用于访问 Packetizer 方法。 demo/ 代码中没有 Packetizer 的示例,tests/ 下的 test_packetizer.py 文件表明它旨在用作原始接口而不是 SSHClient。
所以 - 重申上面简短版本中的问题 -
- 当我看到
paramiko.Packetizer.need_rekey()为True 时,我想我可以通过sleep()ing 来解决这个问题,但是我看不到如何从拥有SSHClient对象的上下文中访问need_rekey()方法。有什么想法吗? - 对于这个问题,我应该考虑其他解决方案吗?
感谢任何帮助!
版本信息仅供参考:
$ python
Python 2.7.5 (default, Apr 9 2015, 11:03:32)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import paramiko
>>> paramiko.__version__
'1.15.2'
>>>
【问题讨论】: