[시큐어코딩 가이드] 2-1-2. 코드 삽입

코드삽입

정의

  • 공격자가 소프트웨어의 의도된 동작을 변경하도록 임의 코드를 삽입해 소프트웨어가 비정상적으로 동작하도록 하는 보안약점을 의미한다.
  • 프로그래밍 언어 자체의 기능에 한해 이루어진다는 점에서 운영체제 명령어 삽입과 다르다. 사용자 입력값에 코드가 포함되는 것을 허용할 경우, 공격자는 코드를 실행해 권한 탈취, 인증우호, 시스템 명령어 실행 등을 할 수 있다.

 

안전한 코딩기법

  • 동적코드를 실행할 수 있는 함수를 사용하지 않는다.
  • 필요시, 동적코드를 입력값으로 받지 않도록 화이트리스트 기반 검증을 해야한다. 또는 유효한 문자만 포함하도록 입력값을 필터링해야한다.

 

코드예제

eval()

안전하지 않은 코드예제입니다. 입력받은 값을 검증없이 eval() 함수의 인자로 사용하고 있습니다. 입력값을 검증없이 사용할 경우 악성 기능 실행을 위한 라이브러리 로드 및 원격 대화형 쉘 등을 실행할 수도 있습니다.

# 코드삽입(안전X)
# msg = compile('for x in range(1):\n import time\n time.sleep(20)','a','single')
def route_bad(request):
	#실행을 위해 GET 사용
    msg = request.GET.get('msg')
    ret = eval(msg)
    return render(request, "success.html", {'data': ret})

 

 

다음은 안전한 코드 예제입니다. 특수문자 등을 필터링 하는 사전검증 코드를 추가하면 코드 삽입 공격 위험을 완화할 수 있습니다. 

  • isalpha(): 문자열이 알파벳으로만 구성되어 있는지 확인
  • isalnum(): 문자열이 알파벳 또는 숫자로만 구성되어 있는지 확인
  • isdecimal(): 문자열이 정수 형태인지 확인
  • isdigit() 문자열이 숫자로 인식될 수 있는 것인지 확인
# 코드삽입(안전O)
def route_good(request):
    msg = request.GET.get('msg')
    if msg.isalnum():
        ret = eval(msg)
        return render(request, "success.html", {'data': ret})
    return render(request, "error.html")

 

 

exec()

안전하지 않은 코드예제입니다. 입력받은 값을 검증없이 exec() 함수의 인자로 사용하고 있습니다. 이렇게 되면 중요 데이터 탈취, 서버의 권한 탈취, 엑세스 거부 등으로 이어질 수 있습니다.

# 코드삽입(안전X)
#function_name=__import__(‘platform’).system
def request_rest_api_bad(request):
    function_name = request.GET.get('function_name', )
    exec('{}()'.format(function_name))
    return render(request, "success.html")

 

안전한 코드 예제입니다. 입력받은 값이 사전에 정의한 화이트리스트에 포함되는지 확인하고, 리스트에 없는 경우 에러를 반환합니다.

def get_friend_list():
    print('OK, 안전')
    
def get_addr():
    print('OK, 안전')
    
def get_phone_num():
    print('OK, 안전')
    
# 코드삽입(안전O)
WHITE_LIST = ['get_friend_list', 'get_addr', 'get_phone_num']
def request_rest_api_good(request):
    function_name = request.GET.get('function_name', )

    if function_name in WHITE_LIST:
        exec('{}()'.format(function_name))
        return render(request, "success.html", {'msg': f'{function_name}은 허용된 함수입니다'})

    return render(request, "error.html", {'msg': '허용되지 않은 함수입니다'})

 

function_name=abc 입력

 

function_name=get_addr 입력

 

 

 

입력데이터 검증 및 표현/코드 삽입

[참고문헌] Python 시큐어코딩 가이드(2022) / KISA(한국인터넷진흥원)