【问题标题】:How to securely escape command line arguments for the cmd.exe shell on Windows?如何在 Windows 上安全地转义 cmd.exe shell 的命令行参数?
【发布时间】:2018-10-14 00:50:00
【问题描述】:

好的,我有一些命令必须在 shell=True 模式下执行。

os.systemsubprocess.Popen(..., shell=True)

此命令包含字符串替换,例如:cmd = "some_secret_command {0}".format(string_from_user)

我想转义 string_from_user 变量以防止任何注入。

简单的错误答案:

  1. 使用shlex.quote - 不正确

print(shlex.quote('file.txxt; &ls . #')) -> 'file.txxt; &ls . #'(注入)

例子:

> python -c "import sys; print(sys.argv[1])" 'file.txxt; &ls . #'
secret.txt
secret2.txt
  1. 使用转义 ^ - 不正确

例子:

import os

CMD = '''string with spaces'''.replace('', '^').replace('^"', '')
os.system('python -c "import sys; print(sys.argv[1])" {0}'.format(CMD))

现在我可以使用(空格)并注入多个参数。

  1. 使用^"' - 不正确

例子:

import os

CMD = '''some arg with spaces'''.replace('', '^').replace('^"', '')
os.system('python -c "import sys; print(sys.argv[1])" "{0}"'.format(CMD))

打印^s^o^m^e^ ^a^r^g^ ^w^i^t^h^ ^s^p^a^c^e^s^

如果'

import os

CMD = '''some spaces'''.replace('', '^').replace('^\'', '')
os.system('python -c "import sys; print(sys.argv[1])" \'{0}\''.format(CMD))

打印'some

我现在知道shell=False,但这对我来说是不正确的。

【问题讨论】:

  • 你有 Windows 标签,你能确认你打算运行哪个 shell,例如cmd.exe?我问的原因是因为所需的引用不同,例如 Powershell 使用反引号。
  • 我的错,我的意思是cmd.exe
  • 为什么需要外壳?我不知道你为什么会需要一个。

标签: python windows cmd


【解决方案1】:

为 windows 引用命令行的问题是有两个分层的解析引擎受您的引号影响。首先,有解释一些特殊字符的 Shell(例如cmd.exe)。然后是被调用程序解析命令行。 Windows 提供的CommandLineToArgvW 函数经常发生这种情况,但并非总是如此。

也就是说,对于一般情况,例如将cmd.exe 与使用CommandLineToArgvW 解析其命令行的程序一起使用,您可以使用Daniel Colascione 在Everyone quotes command line arguments the wrong way 中描述的技术。我最初尝试将其调整为 Ruby,现在尝试将其转换为 python。

import re

def escape_argument(arg):
    # Escape the argument for the cmd.exe shell.
    # See http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
    #
    # First we escape the quote chars to produce a argument suitable for
    # CommandLineToArgvW. We don't need to do this for simple arguments.
  
    if not arg or re.search(r'(["\s])', arg):
        arg = '"' + arg.replace('"', r'\"') + '"'
  
    return escape_for_cmd_exe(arg)

def escape_for_cmd_exe(arg):
    # Escape an argument string to be suitable to be passed to
    # cmd.exe on Windows
    #
    # This method takes an argument that is expected to already be properly
    # escaped for the receiving program to be properly parsed. This argument
    # will be further escaped to pass the interpolation performed by cmd.exe
    # unchanged.
    #
    # Any meta-characters will be escaped, removing the ability to e.g. use
    # redirects or variables.
    #
    # @param arg [String] a single command line argument to escape for cmd.exe
    # @return [String] an escaped string suitable to be passed as a program
    #   argument to cmd.exe

    meta_chars = '()%!^"<>&|'
    meta_re = re.compile('(' + '|'.join(re.escape(char) for char in list(meta_chars)) + ')')
    meta_map = { char: "^%s" % char for char in meta_chars }
  
    def escape_meta_chars(m):
        char = m.group(1)
        return meta_map[char]
    
    return meta_re.sub(escape_meta_chars, arg)

应用此代码,您应该能够成功地为 cmd.exe shell 转义参数。

print escape_argument('''some arg with spaces''')
# ^"some arg with spaces^"

请注意,该方法应引用单个完整参数。如果你从多个来源收集你的参数,例如,通过构建一个 python 代码字符串传递给 python 命令,你必须在将它传递给 escape_argument 之前组装它。

import os

CMD = '''string with spaces and &weird^ charcters!'''
os.system('python -c "import sys; print(sys.argv[1])" {0}'.format(escape_argument(CMD)))
# string with spaces and &weird^ charcters!

【讨论】:

  • 这个答案很好,并且在您启动 Python 子进程时有效,不幸的是,我正在启动一个 .bat 文件作为子进程,一旦我这样做echo %1%,一切都会再次受到破坏:/
猜你喜欢
  • 2011-04-27
  • 2013-04-01
  • 1970-01-01
  • 2012-04-19
  • 2011-09-30
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多