2013-03-25 2 views
2

처음에는 파일 파서를로드해야하는 메인 파이썬 모듈을 작성했습니다. 처음에는 텍스트 파서 모듈 하나만 이었지만 다른 경우에는 더 많은 파서를 추가해야합니다.
parser_class1.py
parser_class2.py
조건부로 모듈로드 Python

가 하나의 모든 실행중인 인스턴스에 필요한
parser_class3.py, 나는 명령 라인으로 부하를 생각하고 있어요 :

mmain.py -p parser_class1 

를 이러한 목적으로 필자는 메인 모듈이 호출 될 때로드 할 파서를 선택하기 위해이 코드를 작성했습니다 :

#!/usr/bin/env python 

import argparse 
aparser = argparse.ArgumentParser() 
aparser.add_argument('-p', 
      action='store', 
      dest='module', 
      help='-p module to import') 
results = aparser.parse_args() 

if not results.module: 
    aparser.error('Error! no module') 
try: 
    exec("import %s" %(results.module)) 
    print '%s imported done!'%(results.module) 
except ImportError, e: 
    print e 

하지만이 방법은 위험하다는 것, 어쩌면 전적이 아니라고 읽었습니다.

그런 다음이 방법이 좋습니까? 아니면 다른 방법을 찾아야합니까? 왜? 감사합니다. 어떤 의견이든 환영합니다.

+0

약'__import __()'은 무엇입니까? – FatalError

답변

1

eval를 사용 __IMPORT__()

__import__()

allowed_modules = ['os', 're', 'your_module', 'parser_class1.py', 'parser_class2.py'] 

if not results.module: 
    aparser.error('Error! no module') 
try: 
    if results.module in allowed_modules: 
     module = __import__(results.module) 
     print '%s imported as "module"'%(results.module) 
    else: 
     print 'hey what are you trying to do?' 
except ImportError, e: 
    print e 

module.your_function(your_data) 

EVAL를 사용하는 방법은 사용자가 컴퓨터에서 코드를 실행할 수 있습니다 - 사용자가 같은 짓을 상상해보십시오. 그러지 마. __import__()은 사용자가 모듈을로드 할 수있게하며 사용자가 임의 코드를 실행할 수 없도록합니다. 그러나 그것은 단지 명백하게 더 안전합니다.

allowed_modules이없는 제안 된 기능은로드 할 때 악의적 인 코드가 실행될 수있는 임의의 모델을로드 할 수 있으므로 위험합니다. 잠재적으로 공격자는 어딘가에 파일 (공유 폴더, ftp 폴더, 웹 서버가 관리하는 업로드 폴더 ...)을로드하고 사용자의 주장을 사용하여 호출 할 수 있습니다. "공격자가"os.py ","re.py "를 쓴 경우 여전히 확인해야 할 더 많은 보안 강화 : allowed_modules를 사용

화이트리스트

문제를 완화하지만 완전히 해결되지 않습니다 python이 먼저 모듈을 검색하므로 스크립트 폴더에 "your_module.py", "parser_class1.py"를 추가하십시오 (docs).

결국 parser_class * .py 코드와 sha1sum처럼 해시 목록을 비교할 수 있습니다.

최종주의 사항 : 실제로 스크립트 폴더에 대한 쓰기 권한이있는 사용자는 절대적으로 안전한 코드를 확보 할 수 없습니다.

+0

btw, 도움말 인수에 오타가 있습니다. "-p"대신 "-i"가 표시됩니다. – furins

+0

이미 수정되었습니다! – chespinoza

5

당신은 실제로 단지 조건부 블록 내부의 import 문을 실행할 수 있습니다 :

if x: 
    import module1a as module1 
else: 
    import module1b as module1 

당신이를 사용하여 다양한 방법으로 다양한 화이트리스트 모듈 수입을 설명 할 수 있지만, 효과적으로 아이디어는 수입 프로그램 미리하는 것입니다, 그리고 나서 본질적으로 GOTO를 사용하여 적절한 수입을 올리십시오. 사용자가 임의의 인수를 가져 오도록하고 싶다면 __import__ 함수가 eval이 아닌 갈 길이 될 것입니다.

업데이트 : 코멘트에 언급 @thedox으로

as module1 섹션은 다른 기본 코드와 유사한 API를로드에 대한 관용적 인 방법입니다. 완전히 다른 API로 완전히 다른 작업을 수행하려는 경우에는 따라야 할 패턴이 아닙니다. 당신이 허용하는 경우

보안에 관해서는
if ...: 
    import module1 
    # do some stuff with module1 ... 

else: 
    import module2 
    # do some stuff with module2 ... 

, 사용자가 어떤 임의의 코드 가져 오기를 일으킬 :이 경우 더 합리적인 패턴은 import 문을 특정 수입에 관련된 코드를 포함하는 것 -set (예 : 자신의 모듈, 아마도?), 사용자 입력에 eval을 사용하는 것과 많이 다르지 않습니다. 그것은 본질적으로 동일한 취약점입니다 : 사용자가 자신의 코드를 실행하도록 프로그램을 얻을 수 있습니다.

나는 사용자가 임의의 모듈을 가져올 수있는 진정한 안전 방법이 있다고 생각하지 않습니다. 예외는 파일 시스템에 대한 액세스 권한이 없기 때문에 가져올 새 코드를 만들 수 없다는 것입니다.이 경우 기본적으로 허용 목록의 경우로 돌아가며 명시 적 허용 목록을 구현하여 향후 업데이트를 방지 할 수 있습니다. 미래의 어느 시점에 사용자가 파일 시스템 액세스를 얻는 경우/때의 취약점.

+3

이것은 os.path와 같은 동일한 API이지만 다른 내장이 있다면 모듈을로드하는 관용적 인 방법입니다. – theodox

+0

모듈이 사용 가능한지 확인하기 위해 확인할 때 관용적인데 동의합니다. 많은 모듈 중 하나를로드해야하는 경우 모듈은 런타임 입력 값에 따라 다릅니다. 일부 패턴은이 패턴에 대해 다른 패턴보다 우수합니다. – marr75

+0

@theodox 및 marr75 : 동의 함. 사용자 입력을 기반으로 가져올 수 있는지 여부에 대한 질문이 더 집중되어 있다고 생각합니다. 그러나 사용자가 _arbitrary_ imports를 실행할 수있게하면 어쨌든 자신의 코드를 소개 할 수 있습니다 ... –

0

구문 분석 함수로 가져올 수있는 모든 모듈을 생각한 다음 사례 문이나 사전을 사용하여 올바른 모듈을로드해야합니다.예를 들어이 예에서 parser_classN 모듈 중 하나를로드하는 것은 비싼 경우

import parser_class1, parser_class2, parser_class3 

parser_map = { 
    'class1': parser_class1, 
    'class2': parser_class2, 
    'class3': parser_class3, 
} 

if not args.module: 
    #report error 
    parser = None 
else: 
    parser = parser_map[args.module] 
#perform work with parser 

, 당신은 (즉, def get_class1(): import parser_class1; return parser_class1를) 람다 또는 모듈을 반환하는 함수를 정의 할 선을 변경할 수 있습니다 parser = parser_map[args.module]()

exec 옵션은 유효하지 않은 사용자 입력을 실행하기 때문에 매우 위험 할 수 있습니다. 여기

mmain.py -p "parser_class1; some_function_or_code_that_is_malicious()" 
+0

모든 모듈을 가져 오는 데 벌점이 있습니까? – chespinoza

+1

각 모듈을로드하는 데 필요한 메모리 및 처리 리소스는 무엇이든간에. 꽤 간단한 파서 클래스를로드하는 것처럼 보이는 (귀하의 예제에서) 그래서 나는 당신이 실제적인 차이를 찾지 못했을 것입니다. 원하는 경우 파서를 대신 반환하는 호출 가능 함수에 매핑 제안을 사용하여 불필요한 모듈로드를 제거 할 수 있습니다. – marr75