如何补偿Paramiko重新密钥失败?

2024-04-30 03:17:08 发布

您现在位置:Python中文网/ 问答频道 /正文

短版:

  • Paramiko在大容量数据期间有一个known issue rekeying 转让
  • 引用的补丁(现在是dist的一部分)通过修改时间来缓解这种情况,但是对于大容量传输来说,如果在重新密钥完成之前有太多的数据流,仍然可以中止连接
  • 我看到的最简单的解决方法是引用paramiko.Packetizer.need_rekey(),然后在数据传输线程返回True时阻塞或休眠

我的问题:

  1. 当我拥有的是paramiko.SSHClient()对象时,如何访问paramiko.Packetizer.need_rekey()的任何参考或示例?
  2. 对于解决这个问题有什么更好的建议吗?

长版:

现代SSH会话需要在经过一定时间或数据后重新键入。如果对重新密钥的请求没有足够快地采取行动,其中“足够快”意味着自请求重新密钥以来已经过了太多时间或过多的数据,则连接将作为安全保护机制中止。在

Paramiko过去在重新密钥请求和重新密钥更新之间有一个非常狭窄的限制:20个数据包。This patch2012年起

Increase(d) the limit of received packets between re-key request & completion from 20 packets to 2**29 packets.

在我的应用程序中,我使用paramiko.transport.open_channel在转发端口上传输大(10-30gb)的数据流。如果我在同一LAN上的两个主机之间执行此操作,则成功率为100%。如果主机在不同的局域网上,并且延迟时间越来越长,它就会开始出现故障,比如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文件表明它被设计成用作原始接口,而不是{}。在

所以-重申上面简短版本中的问题-

  1. 当我看到paramiko.Packetizer.need_rekey()为真时,我想我可以通过sleep()来解决这个问题,但是我不知道如何从拥有SSHClient对象的上下文中访问need_rekey()方法。有什么想法吗?在
  2. 这个问题还有别的解决办法吗?在

感谢任何帮助!在

版本信息仅供参考:

$ 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'
>>>

Tags: 数据对象方法paramiko键入时间密钥need
1条回答
网友
1楼 · 发布于 2024-04-30 03:17:08

我还是很想听听Š2。。。在

我通过黑客攻击和斜杠找到了#1的答案:get_transport返回的transport对象包括一个packetizer对象,可用于解决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
>>> ssh = paramiko.SSHClient()
>>> omkey = paramiko.RSAKey.from_private_key_file('./privkey.rsa')
>>> ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
>>> ssh.connect('gowenfawr.example.com', username='gowenfawr', pkey=omkey)
>>> transport = ssh.get_transport()
>>> transport.packetizer
<paramiko.packet.Packetizer object at 0x7fb121aa5650>
>>> transport.packetizer.need_rekey()
False
>>>

我更新了我的“数据读取”循环来检查transport.packetizer.need_rekey()是否被设置,如果设置了,则使用time.sleep(1)来休眠。以下代码每数据传输进度的1/80打印“.”,并且每当由于请求重新密钥而暂停时,将打印“Z”:

^{pr2}$

这就产生了这种输出

$ grabdata.py gowenfawr.example.com
target is gowenfawr.example.com
Found appropriate kernel version
Setting up data transfer
.....Z.....Z.....Z.....Z......Z.....Z.....Z.....Z.....Z......Z.....Z.....Z.....Z.....Z......Z.....Z...
Transfer complete!
$ 

这告诉我,重新密钥是定期发生的(很好,考虑到正在传输的数据量),并且我在更改后的10多次运行中都无法重现会话中止失败。在

相关问题 更多 >