python의 eval () 대 ast.literal_eval ()을 사용합니까?


176

eval()가능한 해결책으로 나온 코드가있는 상황이 있습니다. 이제는 eval()전에 사용해 본 적이 없지만 잠재적 위험에 대한 많은 정보를 접하게되었습니다. 즉, 나는 그것을 사용하는 것에 대해 매우 조심합니다.

내 상황은 사용자가 입력 한 것입니다.

datamap = raw_input('Provide some data here: ')

datamap사전이 필요한 곳 . 나는 주변을 둘러 보았고 이것이 eval()해결할 수 있다는 것을 알았 습니다. 데이터를 사용하기 전에 입력 유형을 확인할 수 있다고 생각했으며 이는 가능한 보안 예방 조치입니다.

datamap = eval(raw_input('Provide some data here: ')
if not isinstance(datamap, dict):
    return

나는 문서를 읽었으며 이것이 안전한지 확실하지 않습니다. eval은 데이터를 입력하자마자 또는 datamap변수가 호출 된 후 데이터를 평가합니까 ?

는 IS ast모듈의 .literal_eval()유일한 안전 옵션은?

답변:


190

datamap = eval(raw_input('Provide some data here: '))안전하지 않은 것으로 판단 하기 전에 실제로 코드 평가한다는 의미입니다 . 함수가 호출 되 자마자 코드를 평가합니다. 의 위험도eval 참조하십시오 .

ast.literal_eval 입력이 유효한 Python 데이터 유형이 아닌 경우 예외를 발생 시키므로 코드가 입력되지 않으면 실행되지 않습니다.

ast.literal_eval필요할 때마다 사용하십시오 eval. 일반적으로 리터럴 파이썬 문장을 평가해서는 안됩니다.


20
비트 연산자 (또는 오버로드 된 연산자)가 실패하므로 100 % 올바른 조언이 아닙니다. 예 : ast.literal_eval("1 & 1")오류가 발생하지만 eval("1 & 1")그렇지 않습니다.
Daniel van Flymen

1
그냥 궁금해서 "1 & 1"과 같은 것을 기대한다면 표현식 파서 나 무언가를 사용해서는 안됩니까?
thelinuxer

@thelinuxer는 여전히 그렇습니다. 당신 ast.literal_eval은 그와 같은 것을 사용할 수 없을 것입니다 (예를 들어 파서를 수동으로 구현할 수 있습니다).
변동성

104

ast.literal_eval() Python 구문의 작은 하위 집합 만 유효하다고 간주합니다.

제공된 문자열 또는 노드는 문자열, 숫자, 튜플, 목록, dicts, 부울 및 없음과 같은 Python 리터럴 구조로만 구성 될 수 있습니다.

전달 __import__('os').system('rm -rf /a-path-you-really-care-about')로하는 것은 ast.literal_eval()오류를 제기하지만, eval()즐겁게 드라이브를 닦아 주실 것이다.

사용자가 일반 사전 만 입력하게하는 것처럼 보이기 때문에을 사용하십시오 ast.literal_eval(). 그것은 당신이 원하는 것을 안전하게하고 더 이상 아무것도하지 않습니다.


바이트 문자열 (클래스 바이트)도 지원합니다. 예 : b'Hello World '
XChikuX

52

eval : 이것은 매우 강력하지만 신뢰할 수없는 입력에서 평가하기 위해 문자열을 수락하면 매우 위험합니다. 평가되는 문자열이 "os.system ( 'rm -rf /')"이라고 가정하십시오. 실제로 컴퓨터의 모든 파일을 삭제하기 시작합니다.

ast.literal_eval : 파이썬 리터럴 또는 컨테이너 디스플레이를 포함하는 표현식 노드 또는 문자열을 안전하게 평가합니다. 제공된 문자열 또는 노드는 문자열, 바이트, 숫자, 튜플, 목록, dicts, 세트, ​​부울, 없음, 바이트 및 세트와 같은 Python 리터럴 구조로만 구성 될 수 있습니다.

통사론:

eval(expression, globals=None, locals=None)
import ast
ast.literal_eval(node_or_string)

예:

# python 2.x - doesn't accept operators in string format
import ast
ast.literal_eval('[1, 2, 3]')  # output: [1, 2, 3]
ast.literal_eval('1+1') # output: ValueError: malformed string


# python 3.0 -3.6
import ast
ast.literal_eval("1+1") # output : 2
ast.literal_eval("{'a': 2, 'b': 3, 3:'xyz'}") # output : {'a': 2, 'b': 3, 3:'xyz'}
# type dictionary
ast.literal_eval("",{}) # output : Syntax Error required only one parameter
ast.literal_eval("__import__('os').system('rm -rf /')") # output : error

eval("__import__('os').system('rm -rf /')") 
# output : start deleting all the files on your computer.
# restricting using global and local variables
eval("__import__('os').system('rm -rf /')",{'__builtins__':{}},{})
# output : Error due to blocked imports by passing  '__builtins__':{} in global

# But still eval is not safe. we can access and break the code as given below
s = """
(lambda fc=(
lambda n: [
    c for c in 
        ().__class__.__bases__[0].__subclasses__() 
        if c.__name__ == n
    ][0]
):
fc("function")(
    fc("code")(
        0,0,0,0,"KABOOM",(),(),(),"","",0,""
    ),{}
)()
)()
"""
eval(s, {'__builtins__':{}})

위의 코드에서 ().__class__.__bases__[0]객체 자체는 없습니다. 이제 모든 하위 클래스를 인스턴스화 했습니다. 여기서 주요 enter code here목표는 n 이라는 하나의 클래스를 찾는 것입니다.

인스턴스화 된 서브 클래스에서 이의를 제기 code하고 function이의를 제기 해야합니다 . 이것은 CPython객체의 서브 클래스에 액세스하고 시스템을 연결 하는 대체 방법입니다 .

파이썬 3.7부터 ast.literal_eval ()이 더 엄격 해졌습니다. 더 이상 임의의 숫자를 더하거나 뺄 수 없습니다.링크


1
나는 파이썬 2.7을 사용하고 있으며 파이썬 3.x에서 잘 작동하는지 확인했다. 내 나쁜 파이썬 2.7에 그것을 오려고
Mourya

3
ast.literal_eval("1+1")파이썬 3.7에서는 작동하지 않으며 이전에 말했듯이 literal_eval은 소수의 데이터 구조의 리터럴로 제한되어야합니다. 이진 연산을 구문 분석 할 수 없어야합니다.
Sesshu

KABOOM코드 를 설명해 주시겠습니까? 여기 발견 :KABOOM
winklerrr

2
@winklerrr KABOOM은 여기에 잘 설명되어 있습니다 : nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
Elijas

41

파이썬 은 평가에 열중 하므로 나중에 데이터로 무엇을 하든지 상관없이 eval(raw_input(...))사용자 입력이에 도달하자마자 평가합니다 eval. 따라서, 이것은 특히 eval사용자가 입력 할 때 안전하지 않습니다 .

사용하십시오 ast.literal_eval.


예를 들어, 프롬프트에서 이것을 입력하면 매우 나쁘게됩니다.

__import__('os').system('rm -rf /a-path-you-really-care-about')

3

사용자가 제공 한 사전 만 있으면 더 나은 해결책이 json.loads있습니다. 주요 제한 사항은 json dicts에 문자열 키가 필요하다는 것입니다. 또한 리터럴 데이터 만 제공 할 수 있지만이 경우도 마찬가지입니다 literal_eval.


1

나는 붙어 있었다 ast.literal_eval(). IntelliJ IDEA 디버거에서 시도했지만 계속 반환되었습니다.None 디버거 출력으로 .

그러나 나중에 출력에 변수를 할당하고 코드로 인쇄했습니다. 잘 작동했습니다. 공유 코드 예 :

import ast
sample_string = '[{"id":"XYZ_GTTC_TYR", "name":"Suction"}]'
output_value = ast.literal_eval(sample_string)
print(output_value)

파이썬 버전 3.6.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.