[시큐어코딩 가이드] 포맷 스트링 삽입
- 정보보안/시큐어코딩 가이드
- 2022. 8. 9.
■ 입력데이터 검증 및 표현
프로그램 입력 값에 대한 검증 누락 또는 부적절한 검증, 데이터의 잘못된 형식지정, 일관되지 않은 언어셋 사용 등으로 인해 발생되는 보안약점으로 SQL 삽입, 크로스사이트 스크립트(XSS) 등의 공격을 유발할 수 있다.
포맷 스트링 삽입
■ 개요
외부로부터 입력된 값을 검증하지 않고 입·출력 함수의 포맷 문자열로 그대로 사용하는 경우 발생할 수 있는 보안약점이다. 공격자는 포맷 문자열을 이용하여 취약한 프로세스를 공격하거나 메모리 내용을 읽거나 쓸 수 있다. 그 결과, 공격자는 취약한 프로세스의 권한을 취득하여 임의의 코드를 실행 할 수 있다.
Python에서는 문자열의 포맷팅 방법으로 “% formatting”, “str.format”, “f-string” 3가지 방법의 문자열 포맷팅 형식을 제공하고 있다. f-string 방법은 Python 3.6부터 도입된 포맷팅 방법이다. 공격자는 포맷 문자열을 이용하여 내부 정보를 문자열로 만들 수 있으며, 이를 반환하는 경우 내부의 중요 정보가 유출될 수 있다.
■ 안전한 코딩 기법
포맷 문자열을 사용하는 함수를 사용할 때는 사용자 입력 값을 직접적으로 포맷 문자열로 사용하거나 포맷 문자열 생성에 포함시키지 않아야 한다. 사용자에게 입력받은 데이터를 포맷 문자열로 사용하고자 하는 경우에는 서식지정자를 포함하지 않거나 파이썬의 내장함수 또는 내장변수 등이 포함되지 않도록 해야 한다.
코드예제
아래 예시에서는 외부에서 입력받은 문자열을 바로 포맷스트링으로 사용하고 있는데 이는 내부 정보가 외부로 노출될 수 있는 문제를 내포하고 있다.
공격자가 # {user.__init__.__globals__[AUTHENTICATE_KEY]} 형식의 문자열 입력 시 글로벌 변수에 접근하여 AUTHENTICATE_KEY의 값을 탈취 할 수 있다.
안전하지 않은 코드의 예 |
from django.shortcuts import render AUTHENTICATE_KEY = 'Passw0rd' def make_user_message(request): user_info = get_user_info(request.POST.get('user_id', '')) format_string = request.POST.get('msg_format', '') # 내부의 민감한 정보가 외부로 노출될 수 있다. # 사용자가 입력한 문자열을 포맷 문자열로 사용하고 있어 안전하지 않다 message = format_string.format(user=user_info) return render(request, '/user_page', {'message':message}) |
외부에서 입력받은 문자열은 반드시 포맷지정자를 이용하여 바인딩하여 사용하여야 하며 직접적으로 포맷문자열로 사용해서는 안 된다.
안전한 코드의 예 |
from django.shortcuts import render AUTHENTICATE_KEY = 'Passw0rd' def make_user_message(request): user_info = get_user_info(request.POST.get('user_id', '')) # 사용자가 입력한 문자열을 포맷 문자열로 사용하지 않아 안전하다 message = 'user name is {}'.format(user_info.name) return render(request, '/user_page', {'message':message}) |