为了安全地用作命令行参数,对字符串进行转义的最佳方法是什么?我知道使用subprocess.Popen
可以解决这个问题,但是对于paramiko来说,这似乎并不正确。示例:
from subprocess import Popen
Popen(['touch', 'foo;uptime']).wait()
这将创建一个名为foo;uptime
的文件,这正是我想要的。比较:
from paramiko import SSHClient()
from subprocess import list2cmdline
ssh = SSHClient()
#... load host keys and connect to a server
stdin, stdout, stderr = ssh.exec_command(list2cmdline(['touch', 'foo;uptime']))
print stdout.read()
这将创建一个名为foo
的文件,并打印远程主机的正常运行时间。它已将uptime
作为第二个命令执行,而不是将其用作第一个命令touch
的参数的一部分。这不是我想要的。
我试着在发送到list2cmdline
之前和之后用反斜杠转义分号,但最后得到了一个名为foo\;uptime
的文件。
此外,如果使用带有空格的命令而不是uptime
,则可以正常工作:
stdin, stdout, stderr = ssh.exec_command(list2cmdline(['touch', 'foo;echo test']))
print stdout.read()
这将创建一个名为foo;echo test
的文件,因为list2cmdline
用引号将其括起来。
另外,我尝试了pipes.quote()
,它的效果与list2cmdline
相同。
编辑:为了澄清这一点,我需要确保在远程主机上只执行一个命令,而不管接收到什么样的输入数据,这意味着要转义诸如;
、&
和backtick之类的字符。
^{} 是我要找的。
示例:
这将在服务器上创建一个名为
foo;uptime
的文件,这正是我想要的。我已经尝试了所有我能想到的shell元字符,它工作了:
使用
list2cmdline()
没有成功,因为它以Microsoft命令行为目标,该命令行的规则与使用SSH与之通信的POSIX命令行的规则不同。相反,请使用本机Python例程
pipes.quote()
,并小心将其分别应用于命令中的每个参数。这将为SSH提供一个工作命令行:输出小心地引用第二个参数以保护
;
字符:假设远程用户有一个POSIX shell,这应该可以工作:
为什么这么做?
POSIX shell single quotes定义为:
这里的想法是用单引号将字符串括起来。单凭这一点,几乎就足够了——除了一句引语之外,每个字符都会被逐字解释。对于单引号,从单引号字符串(第一个
'
)中删除,添加一个单引号(第\'
),然后恢复单引号字符串(最后一个'
)。这有什么用?
这应该适用于任何POSIX shell。我已经用冲刺和猛击测试过了。Solaris 5.10的
/bin/sh
(我认为它与POSIX不兼容,我找不到它的规范)似乎也可以工作。对于任意的远程主机,我认为这是不可能的。我认为
ssh
将使用远程用户的shell(如/etc/passwd
中配置的)执行您的命令。如果远程用户可能正在运行,例如/usr/bin/python
或git-shell
或其他内容,那么不仅任何引用方案可能会遇到跨外壳的不一致,而且您的命令执行也可能会失败。csh/tcsh公司
稍微有点问题的是,远程用户可能正在运行
tcsh
,因为有些人实际上是在野外运行,并且可能希望paramiko的exec_command
工作。(作为shell的/usr/bin/python
用户可能没有这样的期望…)tcsh似乎主要起作用。然而,我想不出一种方式来引用一个换行符,这样它就会很高兴。在单引号字符串中包含换行符似乎使tcsh不高兴:
除了换行符,我所尝试的一切似乎都与tcsh一起工作(包括单引号、双引号、反斜杠、嵌入制表符、星号等)。
测试外壳逃逸
如果您有一个转义方案,以下是一些您可能需要测试的内容:
\n
,\t
,…)'
,"
,\
)*
、?
、[]
等)|
,&
,||
,&&
,…)换行符值得特别注意。^{} solution 没有正确处理这个问题——它转义了任何非字母数字字符,POSIX shell认为转义的换行符(即,在Python中,两个字母的字符串
"\\\n"
)是零个字符,而不是一个换行符。我认为re.escape
可以正确处理所有其他情况,但使用为正则表达式设计的东西来为shell转义会让我感到害怕。结果可能会成功,但我会担心re.escape
或shell转义规则(如换行符)中的细微情况,或者API中未来可能的更改。您还应该知道转义序列可以在不同的阶段进行处理,这会使测试变得复杂——您只关心shell传递给程序的内容,而不关心程序的功能。使用
printf "%s\n" escaped-string-to-test
可能是最好的选择。echo
的工作异常糟糕:在dash中,echo
内置进程反斜杠转义类似于\n
。使用/bin/echo
通常是安全的,但是在我测试过的Solaris 5.10机器上,它还处理类似\n
的序列。相关问题 更多 >
编程相关推荐