os.system() 호출에서 벗어나는 방법?
os.system()을 사용할 때 명령어에 매개 변수로 전달되는 파일 이름 및 기타 인수를 피할 필요가 있는 경우가 많습니다.이거 어떻게 해요?여러 운영 체제/셸에서 작동하지만 특히 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()에서 제공하는 빠르고 쉬운 솔루션에 관심이 있으며 문자열의 소스는 사용자가 생성하지 않았거나 최소한 신뢰할 수 있는 사용자(나)가 입력했습니다.
shlex.quote()
python 3 이후로 당신이 원하는 것을 합니다.
(python 2와 python 3을 모두 지원하는 데 사용하지만, 주의하십시오.pipes
.10후 3.13될 3.13입니다 3.10되었으며 3.13에 3.1후 3.1입니다 3.1될 3.13 3.1s 3.1
이것이 제가 사용하는 것입니다.
def shellquote(s):
return "'" + s.replace("'", "'\\''") + "'"
셸은 항상 따옴표가 붙은 파일 이름을 허용하고 문제의 프로그램에 전달하기 전에 주변 따옴표를 제거합니다.특히 공백이나 기타 고약한 셸 메타문자가 포함된 파일 이름의 문제를 방지할 수 있습니다.
업데이트: Python 3.3 이상을 사용하는 경우 자신의 롤 대신 shlex.quote를 사용합니다.
아마도 당신은 사용하는 특정한 이유가 있을 것입니다.os.system()
. 하지만 그렇지 않다면 모듈을 사용해야 할 것입니다.파이프를 직접 지정하고 셸을 사용하지 않을 수 있습니다.
다음은 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]
아마도요.subprocess.list2cmdline
더 좋은 샷일까요?
그 파이프들을 주목하세요.인용문은 실제로 파이썬 2.5 및 파이썬 3.1에서 깨져서 사용하기에 안전하지 않습니다. 0-길이 인수를 처리하지 않습니다.
>>> from pipes import quote
>>> args = ['arg1', '', 'arg3']
>>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args))
mycommand arg1 arg3
Python issue 7476을 참조하십시오. Python 2.6 및 3.2 이상 버전으로 수정되었습니다.
os.system은 사용자를 위해 구성된 명령어 셸이 무엇이든 호출하기 때문에 플랫폼 독립적인 방식으로는 할 수 없다고 생각합니다.내 명령 셸은 bash, emacs, ruby 또는 wake3에서 무엇이든 될 수 있습니다.이런 프로그램들 중 일부는 당신이 그들에게 전달하는 논쟁의 종류를 기대하지 않고 있고, 설사 그렇게 했다 하더라도 똑같은 방법으로 탈출한다는 보장이 없습니다.
참고: Python 2.7.x에 대한 답변입니다.
출처에 의하면pipes.quote()
문자열을 /bin/sh에 대한 단일 인수로 안정적으로 인용하는 방법입니다. (버전 2.7 이후로 사용되지 않고 파이썬 3.3에서 최종적으로 공개적으로 공개적으로 다음과 같이 노출되지만)shlex.quote()
기능을 합니다.
반면에.subprocess.list2cmdline()
는 "MSC 런타임과 동일한 규칙을 사용하여 인수 시퀀스를 명령줄 문자열로 변환"하는 방법입니다.
여기, 명령 줄에 대한 문자열 인용의 플랫폼 독립적인 방법이 있습니다.
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)
제가 사용하는 기능은 다음과 같습니다.
def quote_argument(argument):
return '"%s"' % (
argument
.replace('\\', '\\\\')
.replace('"', '\\"')
.replace('$', '\\$')
.replace('`', '\\`')
)
즉, 항상 인수를 큰따옴표로 묶은 다음, 큰따옴표 안에 특수한 문자만 백슬래시 인용합니다.
Bash와에서는 Bash와 UNIX를 사용할 수 .shlex.quote
수됩니다. 예를 들어, 공백과 python 3의 셸은할지도는한을기해고이서s,e해고en기을할지도n한는leo .*
캐릭터:
import os
import shlex
os.system("rm " + shlex.quote(filename))
하지만, 이것은 보안 목적으로는 충분하지 않습니다!명령 인수가 의도하지 않은 방식으로 해석되지 않도록 주의해야 합니다.예를 들어, 파일 이름이 실제로 다음과 같은 경로일 경우에는 어떨까요?../../etc/passwd
? os.system("rm " + shlex.quote(filename))
삭제할 ./etc/passwd
현재 디렉터리에 있는 파일 이름만 삭제할 것으로 예상했을 때!여기서 문제는 셸이 특수 문자를 해석하는 것이 아니라 파일 이름 인수를 해석하지 않는다는 것입니다.rm
단순한 파일명으로, 실제로는 경로로 해석됩니다.
이름이 를 한 이 로 하는 에는 에는 )?-f
이름을 . ? 하는 만으로는 하지 을 하지 만으로는 하는 을 다음을 사용하여 옵션을 비활성화해야 합니다.--
아니면 당신은 한 번의 대시로 시작하지 않는 길을 지나야 합니다../-f
가 되는 것은 서 가 를 하는 가 은 가 하는 를 가 서 은 ,rm
command는 인수를 파일 이름이나 경로 또는 대시로 시작하는 경우 옵션으로 해석합니다.
다음은 보다 안전한 구현입니다.
if os.sep in filename:
raise Exception("Did not expect to find file path separator in file name")
os.system("rm -- " + shlex.quote(filename))
저는 이러한 답변들이 윈도우 상에서 명령 줄 논쟁을 피하기에는 좋지 않은 생각이라고 생각합니다.그 결과를 바탕으로, 사람들은 '나쁜' 캐릭터를 모두 얻었다고 가정하고(그리고 바라면서) 블랙리스트 접근법을 적용하려고 노력하고 있습니다.윈도우는 매우 복잡하고 공격자가 명령줄 인수를 가로챌 수 있는 미래의 모든 종류의 문자가 발견될 수 있습니다.
나는 이미 몇몇 대답들이 윈도우에서 기본 메타문자들을 필터링하는 것을 소홀히 하는 것을 보았습니다 (세미콜론과 같은).제가 생각하는 접근 방식은 훨씬 간단합니다.
- 허용되는 ASCII 문자 목록을 만듭니다.
- 해당 목록에 없는 문자를 모두 제거합니다.
- 슬래시와 큰따옴표를 피합니다.
- 명령 인수를 악의적으로 꺾어서 공백으로 명령어를 전달할 수 없도록 전체 명령어를 큰따옴표로 둘러쌉니다.
기본적인 예:
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
이 함수에는 환경 변수 및 기타 셸 변수를 사용할 수 있는 옵션이 있습니다.이 옵션을 활성화하면 위험이 커지므로 기본적으로 비활성화됩니다.
언급URL : https://stackoverflow.com/questions/35817/how-to-escape-os-system-calls
'sourcecode' 카테고리의 다른 글
Cent OS 5에서 느린 cronjobs (0) | 2023.09.16 |
---|---|
mysql join two table, 그리고 0이 아닌 값을 가진 일치하는 레코드의 필드 이름을 가져옵니다. (0) | 2023.09.16 |
ctrl+c를 사용하여 python 중지 (0) | 2023.09.11 |
괄호와 비교했을 때 어떤 차이가 있습니까? WHERE (a, b)= (1,2) (0) | 2023.09.11 |
C#에서 문자열을 전화번호로 포맷하는 방법 (0) | 2023.09.11 |