如何逃避 os.system() 调用?

2025-01-14 08:50:00
admin
原创
124
摘要:问题描述:使用 os.system() 时,通常需要转义文件名和作为参数传递给命令的其他参数。我该怎么做?最好是可以在多个操作系统/shell 上运行的东西,特别是对于 bash。我目前正在执行以下操作,但确信必须有一个库函数,或者至少有一个更优雅/强大/高效的选项:def sh_escape(s): ...

问题描述:

使用 os.system() 时,通常需要转义文件名和作为参数传递给命令的其他参数。我该怎么做?最好是可以在多个操作系统/shell 上运行的东西,特别是对于 bash。

我目前正在执行以下操作,但确信必须有一个库函数,或者至少有一个更优雅/强大/高效的选项:

def sh_escape(s):
   return s.replace("(","\\(").replace(")","\\)").replace(" ","\\ ")

os.system("cat %s | grep something | sort > %s" 
          % (sh_escape(in_filename), 
             sh_escape(out_filename)))

编辑:我接受了使用引号的简单答案,不知道为什么我没有想到这一点;我猜是因为我来自 Windows,其中 ' 和 " 的行为略有不同。

关于安全性,我理解这种担忧,但在这种情况下,我对 os.system() 提供的快速简便的解决方案感兴趣,并且字符串的来源不是用户生成的,或者至少是由受信任的用户(我)输入的。


解决方案 1:

shlex.quote()从 python 3 开始可以做你想做的事情。

pipes.quote用于支持 Python 2 和 Python 3,但请注意,pipes自 3.10 以来已被弃用,并计划在 3.13 中删除)

解决方案 2:

这是我使用的:

def shellquote(s):
    return "'" + s.replace("'", "'\\''") + "'"

shell 始终会接受带引号的文件名,并在将其传递给相关程序之前删除周围的引号。值得注意的是,这可以避免文件名中包含空格或任何其他令人讨厌的 shell 元字符的问题。

更新:如果您使用的是 Python 3.3 或更高版本,请使用shlex.quote而不是自行使用。

解决方案 3:

也许您有使用 的特定原因os.system()。但如果没有,您可能应该使用subprocess模块。您可以直接指定管道并避免使用 shell。

以下内容来自PEP324:

Replacing shell pipe line
-------------------------

output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

解决方案 4:

也许subprocess.list2cmdline是更好的机会?

解决方案 5:

请注意,pipes.quote 实际上在 Python 2.5 和 Python 3.1 中已损坏且使用不安全——它不处理零长度参数。

>>> from pipes import quote
>>> args = ['arg1', '', 'arg3']
>>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args))
mycommand arg1  arg3

请参阅Python 问题 7476;它已在 Python 2.6 和 3.2 及更新版本中修复。

解决方案 6:

我相信 os.system 只是调用为用户配置的任何命令 shell,所以我认为你不能以独立于平台的方式做到这一点。我的命令 shell 可以是 bash、emacs、ruby 甚至 quake3 中的任何一个。其中一些程序并不期望你传递给它们的参数类型,即使它们期望,也不能保证它们以相同的方式进行转义。

解决方案 7:

注意:这是针对 Python 2.7.x 的答案。

根据来源,是一种“可靠地将字符串引用为/bin/shpipes.quote()的单个参数”的方法。(尽管它从 2.7 版开始就被弃用了,并最终在 Python 3.3 中作为函数公开。)shlex.quote()

另一方面,是一种“将一系列参数转换为命令行字符串,使用与MS C 运行时subprocess.list2cmdline()相同的规则”的方法。

这就是我们为命令行引用字符串的平台无关的方式。

import sys
mswindows = (sys.platform == "win32")

if mswindows:
    from subprocess import list2cmdline
    quote_args = list2cmdline
else:
    # POSIX
    from pipes import quote

    def quote_args(seq):
        return ' '.join(quote(arg) for arg in seq)

用法:

# Quote a single argument
print quote_args(['my argument'])

# Quote multiple arguments
my_args = ['This', 'is', 'my arguments']
print quote_args(my_args)

解决方案 8:

我使用的功能是:

def quote_argument(argument):
    return '"%s"' % (
        argument
        .replace('\\', '\\\\')
        .replace('"', '\\\"')
        .replace('$', '\\$')
        .replace('`', '\\`')
    )

也就是说:我总是将参数括在双引号中,然后用反斜杠引用双引号内的特殊字符。

解决方案 9:

在 Bash 等 UNIX shell 上,您可以shlex.quote在 Python 3 中使用来转义 shell 可能解释的特殊字符,例如空格和*字符:

import os
import shlex

os.system("rm " + shlex.quote(filename))

但是,这对于安全目的来说还不够!您仍然需要小心,不要以非预期的方式解释命令参数。例如,如果文件名实际上是像这样的路径,该怎么办../../etc/passwd?当您只希望它删除在当前目录中找到的文件名时,运行os.system("rm " + shlex.quote(filename))可能会删除/etc/passwd!这里的问题不是 shell 解释特殊字符,而是 filename 参数没有被解释为rm简单的文件名,它实际上被解释为路径。

或者,如果有效文件名以破折号开头,例如 ,会怎么样-f?仅仅传递转义文件名是不够的,您需要使用 禁用选项--,或者您需要传递不以破折号开头的路径,例如./-f。这里的问题不是 shell 解释特殊字符,而是如果参数以破折号开头,rm命令会将参数解释为文件名路径或选项。

这是一个更安全的实现:

if os.sep in filename:
     raise Exception("Did not expect to find file path separator in file name")

os.system("rm -- " + shlex.quote(filename))

解决方案 10:

我认为这些答案对于在 Windows 上转义命令行参数来说不是一个好主意。根据结果:人们试图应用黑名单方法来过滤“坏”字符,假设(并希望)他们能过滤掉所有字符。Windows 非常复杂,将来可能会发现各种各样的字符,这些字符可能允许攻击者劫持命令行参数。

我已经看到一些答案忽略了过滤 Windows 中的基本元字符(例如分号)。我采取的方法要简单得多:

  1. 列出允许的 ASCII 字符。

  2. 删除所有不在该列表中的字符。

  3. 转义斜杠和双引号。

  4. 用双引号将整个命令括起来,这样命令参数就不会被恶意破坏和被空格占用。

一个基本的例子:

def win_arg_escape(arg, allow_vars=0):
    allowed_list = """'"/\\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-. """
    if allow_vars:
        allowed_list += "~%$"

    # Filter out anything that isn't a
    # standard character.
    buf = ""
    for ch in arg:
        if ch in allowed_list:
            buf += ch

    # Escape all slashes.
    buf = buf.replace("\\\", "\\\\\")

    # Escape double quotes.
    buf = buf.replace('"', '""')

    # Surround entire arg with quotes.
    # This avoids spaces breaking a command.
    buf = '"%s"' % (buf)

    return buf

该函数有一个选项可以启用环境变量和其他 shell 变量。启用该选项会带来更多风险,因此默认情况下禁用该选项。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1579  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1355  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   8  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   9  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用